blob: 31ca530ae39375eb008c03a9aeb2711a20ffe149 [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.
Adam Cozzette501ecec2023-09-26 14:36:20 -07003//
Hong Shinb837d172023-11-07 13:24:59 -08004// Use of this source code is governed by a BSD-style
5// license that can be found in the LICENSE file or at
6// https://developers.google.com/open-source/licenses/bsd
Adam Cozzette501ecec2023-09-26 14:36:20 -07007
Adam Cozzette12c7bb02023-09-28 12:54:11 -07008#ifndef UPB_UPB_GENERATOR_PLUGIN_H_
9#define UPB_UPB_GENERATOR_PLUGIN_H_
Adam Cozzette501ecec2023-09-26 14:36:20 -070010
11#include <stdio.h>
12
13#include <string>
14#include <vector>
15#ifdef _WIN32
16#include <fcntl.h>
17#include <io.h>
18#endif
19
20// begin:google_only
21// #ifndef UPB_BOOTSTRAP_STAGE0
Adam Cozzette12c7bb02023-09-28 12:54:11 -070022// #include "google/protobuf/descriptor.upb.h"
23// #include "google/protobuf/compiler/plugin.upb.h"
Adam Cozzette501ecec2023-09-26 14:36:20 -070024// #else
25// #include "google/protobuf/compiler/plugin.upb.h"
26// #include "google/protobuf/descriptor.upb.h"
27// #endif
28// end:google_only
29
30// begin:github_only
31#include "google/protobuf/compiler/plugin.upb.h"
32#include "google/protobuf/descriptor.upb.h"
33// end:github_only
34
35#include "absl/container/flat_hash_set.h"
36#include "absl/log/absl_log.h"
37#include "absl/strings/str_split.h"
38#include "absl/strings/string_view.h"
39#include "upb/reflection/def.hpp"
40
41// Must be last.
42#include "upb/port/def.inc"
43
Adam Cozzette12c7bb02023-09-28 12:54:11 -070044namespace upb {
45namespace generator {
Adam Cozzette501ecec2023-09-26 14:36:20 -070046
47inline std::vector<std::pair<std::string, std::string>> ParseGeneratorParameter(
48 const absl::string_view text) {
49 std::vector<std::pair<std::string, std::string>> ret;
50 for (absl::string_view sp : absl::StrSplit(text, ',', absl::SkipEmpty())) {
51 std::string::size_type equals_pos = sp.find_first_of('=');
52 std::pair<std::string, std::string> value;
53 if (equals_pos == std::string::npos) {
54 value.first = std::string(sp);
55 } else {
56 value.first = std::string(sp.substr(0, equals_pos));
57 value.second = std::string(sp.substr(equals_pos + 1));
58 }
59 ret.push_back(std::move(value));
60 }
61 return ret;
62}
63
64class Plugin {
65 public:
66 Plugin() { ReadRequest(); }
67 ~Plugin() { WriteResponse(); }
68
69 absl::string_view parameter() const {
70 return ToStringView(
71 UPB_DESC(compiler_CodeGeneratorRequest_parameter)(request_));
72 }
73
74 template <class T>
75 void GenerateFilesRaw(T&& func) {
76 absl::flat_hash_set<absl::string_view> files_to_generate;
77 size_t size;
78 const upb_StringView* file_to_generate = UPB_DESC(
79 compiler_CodeGeneratorRequest_file_to_generate)(request_, &size);
80 for (size_t i = 0; i < size; i++) {
81 files_to_generate.insert(
82 {file_to_generate[i].data, file_to_generate[i].size});
83 }
84
85 const UPB_DESC(FileDescriptorProto)* const* files =
86 UPB_DESC(compiler_CodeGeneratorRequest_proto_file)(request_, &size);
87 for (size_t i = 0; i < size; i++) {
88 upb::Status status;
89 absl::string_view name =
90 ToStringView(UPB_DESC(FileDescriptorProto_name)(files[i]));
91 func(files[i], files_to_generate.contains(name));
92 }
93 }
94
95 template <class T>
96 void GenerateFiles(T&& func) {
97 GenerateFilesRaw(
98 [this, &func](const UPB_DESC(FileDescriptorProto) * file_proto,
99 bool generate) {
100 upb::Status status;
101 upb::FileDefPtr file = pool_.AddFile(file_proto, &status);
102 if (!file) {
103 absl::string_view name =
104 ToStringView(UPB_DESC(FileDescriptorProto_name)(file_proto));
105 ABSL_LOG(FATAL) << "Couldn't add file " << name
106 << " to DefPool: " << status.error_message();
107 }
108 if (generate) func(file);
109 });
110 }
111
112 void SetError(absl::string_view error) {
113 char* data =
114 static_cast<char*>(upb_Arena_Malloc(arena_.ptr(), error.size()));
115 memcpy(data, error.data(), error.size());
116 UPB_DESC(compiler_CodeGeneratorResponse_set_error)
117 (response_, upb_StringView_FromDataAndSize(data, error.size()));
118 }
119
120 void AddOutputFile(absl::string_view filename, absl::string_view content) {
121 UPB_DESC(compiler_CodeGeneratorResponse_File)* file = UPB_DESC(
122 compiler_CodeGeneratorResponse_add_file)(response_, arena_.ptr());
123 UPB_DESC(compiler_CodeGeneratorResponse_File_set_name)
124 (file, StringDup(filename));
125 UPB_DESC(compiler_CodeGeneratorResponse_File_set_content)
126 (file, StringDup(content));
127 }
128
129 private:
130 upb::Arena arena_;
131 upb::DefPool pool_;
132 UPB_DESC(compiler_CodeGeneratorRequest) * request_;
133 UPB_DESC(compiler_CodeGeneratorResponse) * response_;
134
135 static absl::string_view ToStringView(upb_StringView sv) {
136 return absl::string_view(sv.data, sv.size);
137 }
138
139 upb_StringView StringDup(absl::string_view s) {
140 char* data =
141 reinterpret_cast<char*>(upb_Arena_Malloc(arena_.ptr(), s.size()));
142 memcpy(data, s.data(), s.size());
143 return upb_StringView_FromDataAndSize(data, s.size());
144 }
145
146 std::string ReadAllStdinBinary() {
147 std::string data;
148#ifdef _WIN32
149 _setmode(_fileno(stdin), _O_BINARY);
150 _setmode(_fileno(stdout), _O_BINARY);
151#endif
152 char buf[4096];
153 while (size_t len = fread(buf, 1, sizeof(buf), stdin)) {
154 data.append(buf, len);
155 }
156 return data;
157 }
158
159 void ReadRequest() {
160 std::string data = ReadAllStdinBinary();
161 request_ = UPB_DESC(compiler_CodeGeneratorRequest_parse)(
162 data.data(), data.size(), arena_.ptr());
163 if (!request_) {
164 ABSL_LOG(FATAL) << "Failed to parse CodeGeneratorRequest";
165 }
166 response_ = UPB_DESC(compiler_CodeGeneratorResponse_new)(arena_.ptr());
Joshua Habermancf3a6f52023-11-07 12:22:10 -0800167
168 int features =
169 UPB_DESC(compiler_CodeGeneratorResponse_FEATURE_PROTO3_OPTIONAL) |
170 UPB_DESC(compiler_CodeGeneratorResponse_FEATURE_SUPPORTS_EDITIONS);
Adam Cozzette501ecec2023-09-26 14:36:20 -0700171 UPB_DESC(compiler_CodeGeneratorResponse_set_supported_features)
Joshua Habermancf3a6f52023-11-07 12:22:10 -0800172 (response_, features);
Mike Kruskalcba41102023-11-30 12:38:49 -0800173 UPB_DESC(compiler_CodeGeneratorResponse_set_minimum_edition)
174 (response_, UPB_DESC(EDITION_PROTO2));
175 UPB_DESC(compiler_CodeGeneratorResponse_set_maximum_edition)
176 (response_, UPB_DESC(EDITION_2023));
Adam Cozzette501ecec2023-09-26 14:36:20 -0700177 }
178
179 void WriteResponse() {
180 size_t size;
181 char* serialized = UPB_DESC(compiler_CodeGeneratorResponse_serialize)(
182 response_, arena_.ptr(), &size);
183 if (!serialized) {
184 ABSL_LOG(FATAL) << "Failed to serialize CodeGeneratorResponse";
185 }
186
187 if (fwrite(serialized, 1, size, stdout) != size) {
188 ABSL_LOG(FATAL) << "Failed to write response to stdout";
189 }
190 }
191};
192
Adam Cozzette12c7bb02023-09-28 12:54:11 -0700193} // namespace generator
194} // namespace upb
Adam Cozzette501ecec2023-09-26 14:36:20 -0700195
196#include "upb/port/undef.inc"
197
Adam Cozzette12c7bb02023-09-28 12:54:11 -0700198#endif // UPB_UPB_GENERATOR_PLUGIN_H_