This CL introduces two new files, names.h and context.h. The former is intended to hold functions that generate the stringified names of things to splat into text templates. The latter holds per-invocation options, and a Context struct that makes it easy to thread extra information throughout the codegen backend. PiperOrigin-RevId: 524366974pull/12463/head
parent
a05c57d43c
commit
7143844db0
7 changed files with 569 additions and 276 deletions
@ -0,0 +1,96 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2023 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "google/protobuf/compiler/rust/context.h" |
||||
|
||||
#include <string> |
||||
#include <utility> |
||||
#include <vector> |
||||
|
||||
#include "absl/algorithm/container.h" |
||||
#include "absl/status/status.h" |
||||
#include "absl/status/statusor.h" |
||||
#include "absl/strings/string_view.h" |
||||
#include "absl/strings/substitute.h" |
||||
#include "google/protobuf/compiler/code_generator.h" |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace rust { |
||||
static constexpr std::pair<absl::string_view, absl::string_view> kMagicValue = { |
||||
"experimental-codegen", |
||||
"enabled", |
||||
}; |
||||
|
||||
absl::StatusOr<Options> Options::Parse(absl::string_view param) { |
||||
std::vector<std::pair<std::string, std::string>> args; |
||||
ParseGeneratorParameter(param, &args); |
||||
|
||||
bool has_experimental_value = absl::c_any_of( |
||||
args, [](std::pair<absl::string_view, absl::string_view> pair) { |
||||
return pair == kMagicValue; |
||||
}); |
||||
|
||||
if (!has_experimental_value) { |
||||
return absl::InvalidArgumentError( |
||||
"The Rust codegen is highly experimental. Future versions will break " |
||||
"existing code. Use at your own risk. You can opt-in by passing " |
||||
"'experimental-codegen=enabled' to '--rust_out'."); |
||||
} |
||||
|
||||
Options opts; |
||||
|
||||
auto kernel_arg = |
||||
absl::c_find_if(args, [](auto& arg) { return arg.first == "kernel"; }); |
||||
if (kernel_arg == args.end()) { |
||||
return absl::InvalidArgumentError( |
||||
"Mandatory option `kernel` missing, please specify `cpp` or " |
||||
"`upb`."); |
||||
} |
||||
|
||||
if (kernel_arg->second == "upb") { |
||||
opts.kernel = Kernel::kUpb; |
||||
} else if (kernel_arg->second == "cpp") { |
||||
opts.kernel = Kernel::kCpp; |
||||
} else { |
||||
return absl::InvalidArgumentError( |
||||
absl::Substitute("Unknown kernel `$0`, please specify `cpp` or " |
||||
"`upb`.", |
||||
kernel_arg->second)); |
||||
} |
||||
|
||||
return opts; |
||||
} |
||||
|
||||
} // namespace rust
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,112 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2023 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_RUST_CONTEXT_H__ |
||||
#define GOOGLE_PROTOBUF_COMPILER_RUST_CONTEXT_H__ |
||||
|
||||
#include "absl/status/statusor.h" |
||||
#include "absl/strings/string_view.h" |
||||
#include "absl/types/span.h" |
||||
#include "google/protobuf/io/printer.h" |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace rust { |
||||
// Marks which kernel the Rust codegen should generate code for.
|
||||
enum class Kernel { |
||||
kUpb, |
||||
kCpp, |
||||
}; |
||||
|
||||
// Global options for a codegen invocation.
|
||||
struct Options { |
||||
Kernel kernel; |
||||
|
||||
static absl::StatusOr<Options> Parse(absl::string_view param); |
||||
}; |
||||
|
||||
// A context for generating a particular kind of definition.
|
||||
// This type acts as an options struct (as in go/totw/173) for most of the
|
||||
// generator.
|
||||
//
|
||||
// `Descriptor` is the type of a descriptor.h class relevant for the current
|
||||
// context.
|
||||
template <typename Descriptor> |
||||
class Context { |
||||
public: |
||||
Context(const Options* opts, const Descriptor* desc, io::Printer* printer) |
||||
: opts_(opts), desc_(desc), printer_(printer) {} |
||||
|
||||
Context(const Context&) = default; |
||||
Context& operator=(const Context&) = default; |
||||
|
||||
const Descriptor& desc() const { return *desc_; } |
||||
const Options& opts() const { return *opts_; } |
||||
|
||||
bool is_cpp() const { return opts_->kernel == Kernel::kCpp; } |
||||
bool is_upb() const { return opts_->kernel == Kernel::kUpb; } |
||||
|
||||
// NOTE: prefer ctx.Emit() over ctx.printer().Emit();
|
||||
io::Printer& printer() const { return *printer_; } |
||||
|
||||
// Creates a new context over a different descriptor.
|
||||
template <typename D> |
||||
Context<D> WithDesc(const D& desc) const { |
||||
return Context<D>(opts_, &desc, printer_); |
||||
} |
||||
|
||||
template <typename D> |
||||
Context<D> WithDesc(const D* desc) const { |
||||
return Context<D>(opts_, desc, printer_); |
||||
} |
||||
|
||||
Context WithPrinter(io::Printer* printer) const { |
||||
return Context(opts_, desc_, printer); |
||||
} |
||||
|
||||
// Forwards to Emit(), which will likely be called all the time.
|
||||
void Emit(absl::string_view format) const { printer_->Emit(format); } |
||||
void Emit(absl::Span<const io::Printer::Sub> vars, |
||||
absl::string_view format) const { |
||||
printer_->Emit(vars, format); |
||||
} |
||||
|
||||
private: |
||||
const Options* opts_; |
||||
const Descriptor* desc_; |
||||
io::Printer* printer_; |
||||
}; |
||||
} // namespace rust
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_RUST_CONTEXT_H__
|
@ -0,0 +1,130 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2023 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "google/protobuf/compiler/rust/naming.h" |
||||
|
||||
#include <string> |
||||
|
||||
#include "absl/log/absl_log.h" |
||||
#include "absl/strings/str_cat.h" |
||||
#include "absl/strings/str_join.h" |
||||
#include "absl/strings/str_replace.h" |
||||
#include "absl/strings/string_view.h" |
||||
#include "absl/strings/substitute.h" |
||||
#include "google/protobuf/compiler/code_generator.h" |
||||
#include "google/protobuf/compiler/rust/context.h" |
||||
#include "google/protobuf/descriptor.h" |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace rust { |
||||
std::string GetCrateName(Context<FileDescriptor> dep) { |
||||
absl::string_view path = dep.desc().name(); |
||||
auto basename = path.substr(path.rfind('/') + 1); |
||||
return absl::StrReplaceAll(basename, {{".", "_"}, {"-", "_"}}); |
||||
} |
||||
|
||||
std::string GetRsFile(Context<FileDescriptor> file) { |
||||
auto basename = StripProto(file.desc().name()); |
||||
switch (auto k = file.opts().kernel) { |
||||
case Kernel::kUpb: |
||||
return absl::StrCat(basename, ".u.pb.rs"); |
||||
case Kernel::kCpp: |
||||
return absl::StrCat(basename, ".c.pb.rs"); |
||||
default: |
||||
ABSL_LOG(FATAL) << "Unknown kernel type: " << static_cast<int>(k); |
||||
return ""; |
||||
} |
||||
} |
||||
|
||||
std::string GetThunkCcFile(Context<FileDescriptor> file) { |
||||
auto basename = StripProto(file.desc().name()); |
||||
return absl::StrCat(basename, ".pb.thunks.cc"); |
||||
} |
||||
|
||||
std::string GetHeaderFile(Context<FileDescriptor> file) { |
||||
auto basename = StripProto(file.desc().name()); |
||||
return absl::StrCat(basename, ".proto.h"); |
||||
} |
||||
|
||||
std::string GetUnderscoreDelimitedFullName(Context<Descriptor> msg) { |
||||
std::string result = msg.desc().full_name(); |
||||
absl::StrReplaceAll({{".", "_"}}, &result); |
||||
return result; |
||||
} |
||||
|
||||
std::string GetAccessorThunkName(Context<FieldDescriptor> field, |
||||
absl::string_view op) { |
||||
std::string thunk = "__rust_proto_thunk__"; |
||||
absl::StrAppend(&thunk, GetUnderscoreDelimitedFullName( |
||||
field.WithDesc(field.desc().containing_type()))); |
||||
absl::SubstituteAndAppend(&thunk, "_$0_$1", op, field.desc().name()); |
||||
return thunk; |
||||
} |
||||
|
||||
absl::string_view PrimitiveRsTypeName(Context<FieldDescriptor> field) { |
||||
switch (field.desc().type()) { |
||||
case FieldDescriptor::TYPE_BOOL: |
||||
return "bool"; |
||||
case FieldDescriptor::TYPE_INT64: |
||||
return "i64"; |
||||
case FieldDescriptor::TYPE_BYTES: |
||||
return "&[u8]"; |
||||
default: |
||||
break; |
||||
} |
||||
ABSL_LOG(FATAL) << "Unsupported field type: " << field.desc().type_name(); |
||||
return ""; |
||||
} |
||||
|
||||
bool IsSupportedFieldType(Context<FieldDescriptor> field) { |
||||
return !field.desc().is_repeated() && |
||||
// We do not support [ctype=FOO] (used to set the field type in C++ to
|
||||
// cord or string_piece) in V0 API.
|
||||
!field.desc().options().has_ctype() && |
||||
(field.desc().type() == FieldDescriptor::TYPE_BOOL || |
||||
field.desc().type() == FieldDescriptor::TYPE_INT64 || |
||||
field.desc().type() == FieldDescriptor::TYPE_BYTES); |
||||
} |
||||
|
||||
std::string RustModule(Context<Descriptor> msg) { |
||||
absl::string_view package = msg.desc().file()->package(); |
||||
if (package.empty()) return ""; |
||||
return absl::StrCat("", absl::StrReplaceAll(package, {{".", "::"}})); |
||||
} |
||||
|
||||
std::string GetCrateRelativeQualifiedPath(Context<Descriptor> msg) { |
||||
return absl::StrCat(RustModule(msg), "::", msg.desc().name()); |
||||
} |
||||
} // namespace rust
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,68 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2023 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_RUST_NAMING_H__ |
||||
#define GOOGLE_PROTOBUF_COMPILER_RUST_NAMING_H__ |
||||
|
||||
#include <string> |
||||
|
||||
#include "absl/strings/string_view.h" |
||||
#include "google/protobuf/compiler/rust/context.h" |
||||
#include "google/protobuf/descriptor.h" |
||||
#include "google/protobuf/descriptor.pb.h" |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace rust { |
||||
std::string GetCrateName(Context<FileDescriptor> dep); |
||||
|
||||
std::string GetRsFile(Context<FileDescriptor> file); |
||||
std::string GetThunkCcFile(Context<FileDescriptor> file); |
||||
std::string GetHeaderFile(Context<FileDescriptor> file); |
||||
|
||||
std::string GetUnderscoreDelimitedFullName(Context<Descriptor> msg); |
||||
|
||||
std::string GetAccessorThunkName(Context<FieldDescriptor> field, |
||||
absl::string_view op); |
||||
|
||||
bool IsSupportedFieldType(Context<FieldDescriptor> field); |
||||
|
||||
absl::string_view PrimitiveRsTypeName(Context<FieldDescriptor> field); |
||||
|
||||
std::string RustModule(Context<Descriptor> msg); |
||||
|
||||
std::string GetCrateRelativeQualifiedPath(Context<Descriptor> msg); |
||||
} // namespace rust
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_RUST_NAMING_H__
|
Loading…
Reference in new issue