1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2023 Google LLC. All rights reserved.
3 //
4 // 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
7
8 #include "google/protobuf/compiler/rust/context.h"
9
10 #include <string>
11 #include <utility>
12 #include <vector>
13
14 #include "absl/algorithm/container.h"
15 #include "absl/status/status.h"
16 #include "absl/status/statusor.h"
17 #include "absl/strings/string_view.h"
18 #include "absl/strings/substitute.h"
19 #include "google/protobuf/compiler/code_generator.h"
20 #include "google/protobuf/descriptor.h"
21
22 namespace google {
23 namespace protobuf {
24 namespace compiler {
25 namespace rust {
26 static constexpr std::pair<absl::string_view, absl::string_view> kMagicValue = {
27 "experimental-codegen",
28 "enabled",
29 };
30
Parse(absl::string_view param)31 absl::StatusOr<Options> Options::Parse(absl::string_view param) {
32 std::vector<std::pair<std::string, std::string>> args;
33 ParseGeneratorParameter(param, &args);
34
35 bool has_experimental_value = absl::c_any_of(
36 args, [](std::pair<absl::string_view, absl::string_view> pair) {
37 return pair == kMagicValue;
38 });
39
40 if (!has_experimental_value) {
41 return absl::InvalidArgumentError(
42 "The Rust codegen is highly experimental. Future versions will break "
43 "existing code. Use at your own risk. You can opt-in by passing "
44 "'experimental-codegen=enabled' to '--rust_opt'.");
45 }
46
47 Options opts;
48
49 auto kernel_arg =
50 absl::c_find_if(args, [](auto& arg) { return arg.first == "kernel"; });
51 if (kernel_arg == args.end()) {
52 return absl::InvalidArgumentError(
53 "Mandatory option `kernel` missing, please specify `cpp` or "
54 "`upb`.");
55 }
56
57 if (kernel_arg->second == "upb") {
58 opts.kernel = Kernel::kUpb;
59 } else if (kernel_arg->second == "cpp") {
60 opts.kernel = Kernel::kCpp;
61 } else {
62 return absl::InvalidArgumentError(
63 absl::Substitute("Unknown kernel `$0`, please specify `cpp` or "
64 "`upb`.",
65 kernel_arg->second));
66 }
67
68 auto mapping_arg = absl::c_find_if(
69 args, [](auto& arg) { return arg.first == "bazel_crate_mapping"; });
70 if (mapping_arg != args.end()) {
71 opts.mapping_file_path = mapping_arg->second;
72 }
73
74 auto strip_nonfunctional_codegen_arg = absl::c_find_if(args, [](auto& arg) {
75 return arg.first == "experimental_strip_nonfunctional_codegen";
76 });
77 if (strip_nonfunctional_codegen_arg != args.end()) {
78 opts.strip_nonfunctional_codegen = true;
79 }
80
81 return opts;
82 }
83
IsInCurrentlyGeneratingCrate(Context & ctx,const FileDescriptor & file)84 bool IsInCurrentlyGeneratingCrate(Context& ctx, const FileDescriptor& file) {
85 return ctx.generator_context().is_file_in_current_crate(file);
86 }
87
IsInCurrentlyGeneratingCrate(Context & ctx,const Descriptor & message)88 bool IsInCurrentlyGeneratingCrate(Context& ctx, const Descriptor& message) {
89 return IsInCurrentlyGeneratingCrate(ctx, *message.file());
90 }
91
IsInCurrentlyGeneratingCrate(Context & ctx,const EnumDescriptor & enum_)92 bool IsInCurrentlyGeneratingCrate(Context& ctx, const EnumDescriptor& enum_) {
93 return IsInCurrentlyGeneratingCrate(ctx, *enum_.file());
94 }
95
96 } // namespace rust
97 } // namespace compiler
98 } // namespace protobuf
99 } // namespace google
100