blob: 50ff5498bf4d3b9950d7e8f3aa0e41b453417363 [file] [log] [blame]
Adam Cozzette501ecec2023-09-26 14:36:20 -07001// Protocol Buffers - Google's data interchange format
2// Copyright 2023 Google LLC. All rights reserved.
3// https://developers.google.com/protocol-buffers/
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
8//
9// * Redistributions of source code must retain the above copyright
10// notice, this list of conditions and the following disclaimer.
11// * Redistributions in binary form must reproduce the above
12// copyright notice, this list of conditions and the following disclaimer
13// in the documentation and/or other materials provided with the
14// distribution.
15// * Neither the name of Google LLC nor the names of its
16// contributors may be used to endorse or promote products derived from
17// this software without specific prior written permission.
18//
19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
Adam Cozzette12c7bb02023-09-28 12:54:11 -070031#ifndef UPB_UPB_GENERATOR_PLUGIN_H_
32#define UPB_UPB_GENERATOR_PLUGIN_H_
Adam Cozzette501ecec2023-09-26 14:36:20 -070033
34#include <stdio.h>
35
36#include <string>
37#include <vector>
38#ifdef _WIN32
39#include <fcntl.h>
40#include <io.h>
41#endif
42
43// begin:google_only
44// #ifndef UPB_BOOTSTRAP_STAGE0
Adam Cozzette12c7bb02023-09-28 12:54:11 -070045// #include "google/protobuf/descriptor.upb.h"
46// #include "google/protobuf/compiler/plugin.upb.h"
Adam Cozzette501ecec2023-09-26 14:36:20 -070047// #else
48// #include "google/protobuf/compiler/plugin.upb.h"
49// #include "google/protobuf/descriptor.upb.h"
50// #endif
51// end:google_only
52
53// begin:github_only
54#include "google/protobuf/compiler/plugin.upb.h"
55#include "google/protobuf/descriptor.upb.h"
56// end:github_only
57
58#include "absl/container/flat_hash_set.h"
59#include "absl/log/absl_log.h"
60#include "absl/strings/str_split.h"
61#include "absl/strings/string_view.h"
62#include "upb/reflection/def.hpp"
63
64// Must be last.
65#include "upb/port/def.inc"
66
Adam Cozzette12c7bb02023-09-28 12:54:11 -070067namespace upb {
68namespace generator {
Adam Cozzette501ecec2023-09-26 14:36:20 -070069
70inline std::vector<std::pair<std::string, std::string>> ParseGeneratorParameter(
71 const absl::string_view text) {
72 std::vector<std::pair<std::string, std::string>> ret;
73 for (absl::string_view sp : absl::StrSplit(text, ',', absl::SkipEmpty())) {
74 std::string::size_type equals_pos = sp.find_first_of('=');
75 std::pair<std::string, std::string> value;
76 if (equals_pos == std::string::npos) {
77 value.first = std::string(sp);
78 } else {
79 value.first = std::string(sp.substr(0, equals_pos));
80 value.second = std::string(sp.substr(equals_pos + 1));
81 }
82 ret.push_back(std::move(value));
83 }
84 return ret;
85}
86
87class Plugin {
88 public:
89 Plugin() { ReadRequest(); }
90 ~Plugin() { WriteResponse(); }
91
92 absl::string_view parameter() const {
93 return ToStringView(
94 UPB_DESC(compiler_CodeGeneratorRequest_parameter)(request_));
95 }
96
97 template <class T>
98 void GenerateFilesRaw(T&& func) {
99 absl::flat_hash_set<absl::string_view> files_to_generate;
100 size_t size;
101 const upb_StringView* file_to_generate = UPB_DESC(
102 compiler_CodeGeneratorRequest_file_to_generate)(request_, &size);
103 for (size_t i = 0; i < size; i++) {
104 files_to_generate.insert(
105 {file_to_generate[i].data, file_to_generate[i].size});
106 }
107
108 const UPB_DESC(FileDescriptorProto)* const* files =
109 UPB_DESC(compiler_CodeGeneratorRequest_proto_file)(request_, &size);
110 for (size_t i = 0; i < size; i++) {
111 upb::Status status;
112 absl::string_view name =
113 ToStringView(UPB_DESC(FileDescriptorProto_name)(files[i]));
114 func(files[i], files_to_generate.contains(name));
115 }
116 }
117
118 template <class T>
119 void GenerateFiles(T&& func) {
120 GenerateFilesRaw(
121 [this, &func](const UPB_DESC(FileDescriptorProto) * file_proto,
122 bool generate) {
123 upb::Status status;
124 upb::FileDefPtr file = pool_.AddFile(file_proto, &status);
125 if (!file) {
126 absl::string_view name =
127 ToStringView(UPB_DESC(FileDescriptorProto_name)(file_proto));
128 ABSL_LOG(FATAL) << "Couldn't add file " << name
129 << " to DefPool: " << status.error_message();
130 }
131 if (generate) func(file);
132 });
133 }
134
135 void SetError(absl::string_view error) {
136 char* data =
137 static_cast<char*>(upb_Arena_Malloc(arena_.ptr(), error.size()));
138 memcpy(data, error.data(), error.size());
139 UPB_DESC(compiler_CodeGeneratorResponse_set_error)
140 (response_, upb_StringView_FromDataAndSize(data, error.size()));
141 }
142
143 void AddOutputFile(absl::string_view filename, absl::string_view content) {
144 UPB_DESC(compiler_CodeGeneratorResponse_File)* file = UPB_DESC(
145 compiler_CodeGeneratorResponse_add_file)(response_, arena_.ptr());
146 UPB_DESC(compiler_CodeGeneratorResponse_File_set_name)
147 (file, StringDup(filename));
148 UPB_DESC(compiler_CodeGeneratorResponse_File_set_content)
149 (file, StringDup(content));
150 }
151
152 private:
153 upb::Arena arena_;
154 upb::DefPool pool_;
155 UPB_DESC(compiler_CodeGeneratorRequest) * request_;
156 UPB_DESC(compiler_CodeGeneratorResponse) * response_;
157
158 static absl::string_view ToStringView(upb_StringView sv) {
159 return absl::string_view(sv.data, sv.size);
160 }
161
162 upb_StringView StringDup(absl::string_view s) {
163 char* data =
164 reinterpret_cast<char*>(upb_Arena_Malloc(arena_.ptr(), s.size()));
165 memcpy(data, s.data(), s.size());
166 return upb_StringView_FromDataAndSize(data, s.size());
167 }
168
169 std::string ReadAllStdinBinary() {
170 std::string data;
171#ifdef _WIN32
172 _setmode(_fileno(stdin), _O_BINARY);
173 _setmode(_fileno(stdout), _O_BINARY);
174#endif
175 char buf[4096];
176 while (size_t len = fread(buf, 1, sizeof(buf), stdin)) {
177 data.append(buf, len);
178 }
179 return data;
180 }
181
182 void ReadRequest() {
183 std::string data = ReadAllStdinBinary();
184 request_ = UPB_DESC(compiler_CodeGeneratorRequest_parse)(
185 data.data(), data.size(), arena_.ptr());
186 if (!request_) {
187 ABSL_LOG(FATAL) << "Failed to parse CodeGeneratorRequest";
188 }
189 response_ = UPB_DESC(compiler_CodeGeneratorResponse_new)(arena_.ptr());
Joshua Habermancf3a6f52023-11-07 12:22:10 -0800190
191 int features =
192 UPB_DESC(compiler_CodeGeneratorResponse_FEATURE_PROTO3_OPTIONAL) |
193 UPB_DESC(compiler_CodeGeneratorResponse_FEATURE_SUPPORTS_EDITIONS);
Adam Cozzette501ecec2023-09-26 14:36:20 -0700194 UPB_DESC(compiler_CodeGeneratorResponse_set_supported_features)
Joshua Habermancf3a6f52023-11-07 12:22:10 -0800195 (response_, features);
Adam Cozzette501ecec2023-09-26 14:36:20 -0700196 }
197
198 void WriteResponse() {
199 size_t size;
200 char* serialized = UPB_DESC(compiler_CodeGeneratorResponse_serialize)(
201 response_, arena_.ptr(), &size);
202 if (!serialized) {
203 ABSL_LOG(FATAL) << "Failed to serialize CodeGeneratorResponse";
204 }
205
206 if (fwrite(serialized, 1, size, stdout) != size) {
207 ABSL_LOG(FATAL) << "Failed to write response to stdout";
208 }
209 }
210};
211
Adam Cozzette12c7bb02023-09-28 12:54:11 -0700212} // namespace generator
213} // namespace upb
Adam Cozzette501ecec2023-09-26 14:36:20 -0700214
215#include "upb/port/undef.inc"
216
Adam Cozzette12c7bb02023-09-28 12:54:11 -0700217#endif // UPB_UPB_GENERATOR_PLUGIN_H_