Clean up of rust messagegenerator and accessor generators.

It ended up being odd to construct the AccessorGenerators ahead of time given some specific Context<>: since each of the three methods on AccessorGenerators demands a different Context than the initial one so they shouldn't hold that Context anyway. It ended up just being a spooky parallel array to the Fields with an unenforced invariant that all methods would be called with a new Context<> but the same underlying FieldDescriptor later.

PiperOrigin-RevId: 558770643
pull/13617/head
Protobuf Team Bot 1 year ago committed by Copybara-Service
parent da38af7191
commit 34585e9d2f
  1. 6
      src/google/protobuf/compiler/rust/BUILD.bazel
  2. 123
      src/google/protobuf/compiler/rust/accessors/accessor_generator.h
  3. 44
      src/google/protobuf/compiler/rust/accessors/accessors.cc
  4. 57
      src/google/protobuf/compiler/rust/accessors/accessors.h
  5. 130
      src/google/protobuf/compiler/rust/accessors/singular_bytes.cc
  6. 47
      src/google/protobuf/compiler/rust/accessors/singular_message.cc
  7. 144
      src/google/protobuf/compiler/rust/accessors/singular_scalar.cc
  8. 51
      src/google/protobuf/compiler/rust/accessors/unsupported_field.cc
  9. 5
      src/google/protobuf/compiler/rust/generator.cc
  10. 42
      src/google/protobuf/compiler/rust/message.cc
  11. 16
      src/google/protobuf/compiler/rust/message.h

@ -53,8 +53,12 @@ cc_library(
"accessors/singular_bytes.cc",
"accessors/singular_message.cc",
"accessors/singular_scalar.cc",
"accessors/unsupported_field.cc",
],
hdrs = [
"accessors/accessors.h",
"accessors/accessor_generator.h",
],
hdrs = ["accessors/accessors.h"],
copts = COPTS,
include_prefix = "google/protobuf/compiler/rust",
deps = [

@ -0,0 +1,123 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2023 Google LLC. 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 LLC. 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_ACCESSORS_ACCESSOR_GENERATOR_H__
#define GOOGLE_PROTOBUF_COMPILER_RUST_ACCESSORS_ACCESSOR_GENERATOR_H__
#include <memory>
#include "absl/log/absl_check.h"
#include "google/protobuf/compiler/rust/context.h"
#include "google/protobuf/descriptor.h"
namespace google {
namespace protobuf {
namespace compiler {
namespace rust {
class AccessorGenerator {
public:
AccessorGenerator() = default;
virtual ~AccessorGenerator() = default;
AccessorGenerator(const AccessorGenerator &) = delete;
AccessorGenerator(AccessorGenerator &&) = delete;
AccessorGenerator &operator=(const AccessorGenerator &) = delete;
AccessorGenerator &operator=(AccessorGenerator &&) = delete;
// Constructs a generator for the given field.
//
// Returns `nullptr` if there is no known generator for this field.
static std::unique_ptr<AccessorGenerator> For(Context<FieldDescriptor> field);
void GenerateMsgImpl(Context<FieldDescriptor> field) const {
InMsgImpl(field);
}
void GenerateExternC(Context<FieldDescriptor> field) const {
InExternC(field);
}
void GenerateThunkCc(Context<FieldDescriptor> field) const {
ABSL_CHECK(field.is_cpp());
InThunkCc(field);
}
private:
// Note: the virtual functions are duplicated as non-virtual public functions,
// so that we can customize prologue and epilogue behavior for these
// functions. For example, consider calling `field.printer.WithVars()` as a
// prologue to inject variables automatically.
// Called inside the main inherent `impl Msg {}` block.
virtual void InMsgImpl(Context<FieldDescriptor> field) const {}
// Called inside of a message's `extern "C" {}` block.
virtual void InExternC(Context<FieldDescriptor> field) const {}
// Called inside of an `extern "C" {}` block in the `.thunk.cc` file, if such
// a file is being generated.
virtual void InThunkCc(Context<FieldDescriptor> field) const {}
};
class SingularScalar final : public AccessorGenerator {
public:
~SingularScalar() override = default;
void InMsgImpl(Context<FieldDescriptor> field) const override;
void InExternC(Context<FieldDescriptor> field) const override;
void InThunkCc(Context<FieldDescriptor> field) const override;
};
class SingularBytes final : public AccessorGenerator {
public:
~SingularBytes() override = default;
void InMsgImpl(Context<FieldDescriptor> field) const override;
void InExternC(Context<FieldDescriptor> field) const override;
void InThunkCc(Context<FieldDescriptor> field) const override;
};
class SingularMessage final : public AccessorGenerator {
public:
~SingularMessage() override = default;
void InMsgImpl(Context<FieldDescriptor> field) const override;
void InExternC(Context<FieldDescriptor> field) const override;
void InThunkCc(Context<FieldDescriptor> field) const override;
};
class UnsupportedField final : public AccessorGenerator {
public:
~UnsupportedField() override = default;
void InMsgImpl(Context<FieldDescriptor> field) const override;
};
} // namespace rust
} // namespace compiler
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_COMPILER_RUST_ACCESSORS_ACCESSOR_GENERATOR_H__

@ -32,6 +32,7 @@
#include <memory>
#include "google/protobuf/compiler/rust/accessors/accessor_generator.h"
#include "google/protobuf/compiler/rust/context.h"
#include "google/protobuf/descriptor.h"
#include "google/protobuf/descriptor.pb.h"
@ -40,15 +41,22 @@ namespace google {
namespace protobuf {
namespace compiler {
namespace rust {
std::unique_ptr<AccessorGenerator> AccessorGenerator::For(
Context<FieldDescriptor> field) {
namespace {
std::unique_ptr<AccessorGenerator> AccessorGeneratorFor(
const FieldDescriptor& desc) {
// We do not support [ctype=FOO] (used to set the field type in C++ to
// cord or string_piece) in V0 API.
if (field.desc().options().has_ctype()) {
return nullptr;
if (desc.options().has_ctype()) {
return std::make_unique<UnsupportedField>();
}
if (desc.is_repeated()) {
return std::make_unique<UnsupportedField>();
}
switch (field.desc().type()) {
switch (desc.type()) {
case FieldDescriptor::TYPE_INT32:
case FieldDescriptor::TYPE_INT64:
case FieldDescriptor::TYPE_FIXED32:
@ -62,19 +70,31 @@ std::unique_ptr<AccessorGenerator> AccessorGenerator::For(
case FieldDescriptor::TYPE_FLOAT:
case FieldDescriptor::TYPE_DOUBLE:
case FieldDescriptor::TYPE_BOOL:
if (field.desc().is_repeated()) return nullptr;
return ForSingularScalar(field);
return std::make_unique<SingularScalar>();
case FieldDescriptor::TYPE_BYTES:
if (field.desc().is_repeated()) return nullptr;
return ForSingularBytes(field);
return std::make_unique<SingularBytes>();
case FieldDescriptor::TYPE_MESSAGE:
if (field.desc().is_repeated()) return nullptr;
return ForSingularMessage(field);
return std::make_unique<SingularMessage>();
default:
return nullptr;
return std::make_unique<UnsupportedField>();
}
}
} // namespace
void GenerateAccessorMsgImpl(Context<FieldDescriptor> field) {
AccessorGeneratorFor(field.desc())->GenerateMsgImpl(field);
}
void GenerateAccessorExternC(Context<FieldDescriptor> field) {
AccessorGeneratorFor(field.desc())->GenerateExternC(field);
}
void GenerateAccessorThunkCc(Context<FieldDescriptor> field) {
AccessorGeneratorFor(field.desc())->GenerateThunkCc(field);
}
} // namespace rust
} // namespace compiler
} // namespace protobuf

@ -31,9 +31,6 @@
#ifndef GOOGLE_PROTOBUF_COMPILER_RUST_ACCESSORS_ACCESSORS_H__
#define GOOGLE_PROTOBUF_COMPILER_RUST_ACCESSORS_ACCESSORS_H__
#include <memory>
#include "absl/log/absl_check.h"
#include "google/protobuf/compiler/rust/context.h"
#include "google/protobuf/descriptor.h"
@ -42,57 +39,9 @@ namespace protobuf {
namespace compiler {
namespace rust {
class AccessorGenerator {
public:
AccessorGenerator() = default;
virtual ~AccessorGenerator() = default;
AccessorGenerator(const AccessorGenerator &) = delete;
AccessorGenerator(AccessorGenerator &&) = delete;
AccessorGenerator &operator=(const AccessorGenerator &) = delete;
AccessorGenerator &operator=(AccessorGenerator &&) = delete;
// Constructs a generator for the given field.
//
// Returns `nullptr` if there is no known generator for this field.
static std::unique_ptr<AccessorGenerator> For(Context<FieldDescriptor> field);
void GenerateMsgImpl(Context<FieldDescriptor> field) const {
InMsgImpl(field);
}
void GenerateExternC(Context<FieldDescriptor> field) const {
InExternC(field);
}
void GenerateThunkCc(Context<FieldDescriptor> field) const {
ABSL_CHECK(field.is_cpp());
InThunkCc(field);
}
private:
// Note: the virtual functions are duplicated as non-virtual public functions,
// so that we can customize prologue and epilogue behavior for these
// functions. For example, consider calling `field.printer.WithVars()` as a
// prologue to inject variables automatically.
// Called inside the main inherent `impl Msg {}` block.
virtual void InMsgImpl(Context<FieldDescriptor> field) const {}
// Called inside of a message's `extern "C" {}` block.
virtual void InExternC(Context<FieldDescriptor> field) const {}
// Called inside of an `extern "C" {}` block in the `.thunk.cc` file, if such
// a file is being generated.
virtual void InThunkCc(Context<FieldDescriptor> field) const {}
// These static factories are defined in the corresponding implementation
// files for each implementation of AccessorGenerator.
static std::unique_ptr<AccessorGenerator> ForSingularScalar(
Context<FieldDescriptor> field);
static std::unique_ptr<AccessorGenerator> ForSingularBytes(
Context<FieldDescriptor> field);
static std::unique_ptr<AccessorGenerator> ForSingularMessage(
Context<FieldDescriptor> field);
};
void GenerateAccessorMsgImpl(Context<FieldDescriptor> field);
void GenerateAccessorExternC(Context<FieldDescriptor> field);
void GenerateAccessorThunkCc(Context<FieldDescriptor> field);
} // namespace rust
} // namespace compiler

@ -28,11 +28,9 @@
// (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 <memory>
#include "absl/strings/string_view.h"
#include "google/protobuf/compiler/cpp/helpers.h"
#include "google/protobuf/compiler/rust/accessors/accessors.h"
#include "google/protobuf/compiler/rust/accessors/accessor_generator.h"
#include "google/protobuf/compiler/rust/context.h"
#include "google/protobuf/compiler/rust/naming.h"
#include "google/protobuf/descriptor.h"
@ -41,24 +39,20 @@ namespace google {
namespace protobuf {
namespace compiler {
namespace rust {
namespace {
class SingularBytes final : public AccessorGenerator {
public:
~SingularBytes() override = default;
void InMsgImpl(Context<FieldDescriptor> field) const override {
field.Emit(
{
{"field", field.desc().name()},
{"hazzer_thunk", Thunk(field, "has")},
{"getter_thunk", Thunk(field, "get")},
{"setter_thunk", Thunk(field, "set")},
{"clearer_thunk", Thunk(field, "clear")},
{"getter_opt",
[&] {
if (!field.desc().is_optional()) return;
if (!field.desc().has_presence()) return;
field.Emit({}, R"rs(
void SingularBytes::InMsgImpl(Context<FieldDescriptor> field) const {
field.Emit(
{
{"field", field.desc().name()},
{"hazzer_thunk", Thunk(field, "has")},
{"getter_thunk", Thunk(field, "get")},
{"setter_thunk", Thunk(field, "set")},
{"clearer_thunk", Thunk(field, "clear")},
{"getter_opt",
[&] {
if (!field.desc().is_optional()) return;
if (!field.desc().has_presence()) return;
field.Emit({}, R"rs(
pub fn $field$_opt(&self) -> Option<&[u8]> {
if !unsafe { $hazzer_thunk$(self.msg) } {
return None;
@ -67,9 +61,9 @@ class SingularBytes final : public AccessorGenerator {
Some($getter_thunk$(self.msg).as_ref())
}
})rs");
}},
},
R"rs(
}},
},
R"rs(
pub fn r#$field$(&self) -> &[u8] {
unsafe { $getter_thunk$(self.msg).as_ref() }
}
@ -86,65 +80,59 @@ class SingularBytes final : public AccessorGenerator {
}
}
)rs");
}
}
void InExternC(Context<FieldDescriptor> field) const override {
field.Emit({{"hazzer_thunk", Thunk(field, "has")},
{"getter_thunk", Thunk(field, "get")},
{"setter_thunk", Thunk(field, "set")},
{"clearer_thunk", Thunk(field, "clear")},
{"hazzer",
[&] {
if (field.desc().has_presence()) {
field.Emit(R"rs(
void SingularBytes::InExternC(Context<FieldDescriptor> field) const {
field.Emit({{"hazzer_thunk", Thunk(field, "has")},
{"getter_thunk", Thunk(field, "get")},
{"setter_thunk", Thunk(field, "set")},
{"clearer_thunk", Thunk(field, "clear")},
{"hazzer",
[&] {
if (field.desc().has_presence()) {
field.Emit(R"rs(
fn $hazzer_thunk$(raw_msg: $pbi$::RawMessage) -> bool;
)rs");
}
}}},
R"rs(
}
}}},
R"rs(
$hazzer$
fn $getter_thunk$(raw_msg: $pbi$::RawMessage) -> $pbi$::PtrAndLen;
fn $setter_thunk$(raw_msg: $pbi$::RawMessage, val: *const u8, len: usize);
fn $clearer_thunk$(raw_msg: $pbi$::RawMessage);
)rs");
}
}
void InThunkCc(Context<FieldDescriptor> field) const override {
field.Emit({{"field", field.desc().name()},
{"QualifiedMsg",
cpp::QualifiedClassName(field.desc().containing_type())},
{"hazzer_thunk", Thunk(field, "has")},
{"getter_thunk", Thunk(field, "get")},
{"setter_thunk", Thunk(field, "set")},
{"clearer_thunk", Thunk(field, "clear")},
{"hazzer",
[&] {
if (field.desc().has_presence()) {
field.Emit(R"cc(
bool $hazzer_thunk$($QualifiedMsg$* msg) {
return msg->has_$field$();
})cc");
}
}}},
R"cc(
$hazzer$;
::google::protobuf::rust_internal::PtrAndLen $getter_thunk$($QualifiedMsg$* msg) {
absl::string_view val = msg->$field$();
return google::protobuf::rust_internal::PtrAndLen(val.data(), val.size());
void SingularBytes::InThunkCc(Context<FieldDescriptor> field) const {
field.Emit({{"field", field.desc().name()},
{"QualifiedMsg",
cpp::QualifiedClassName(field.desc().containing_type())},
{"hazzer_thunk", Thunk(field, "has")},
{"getter_thunk", Thunk(field, "get")},
{"setter_thunk", Thunk(field, "set")},
{"clearer_thunk", Thunk(field, "clear")},
{"hazzer",
[&] {
if (field.desc().has_presence()) {
field.Emit(R"cc(
bool $hazzer_thunk$($QualifiedMsg$* msg) {
return msg->has_$field$();
})cc");
}
void $setter_thunk$($QualifiedMsg$* msg, const char* ptr, ::std::size_t size) {
msg->set_$field$(absl::string_view(ptr, size));
}
void $clearer_thunk$($QualifiedMsg$* msg) { msg->clear_$field$(); }
)cc");
}
};
} // namespace
std::unique_ptr<AccessorGenerator> AccessorGenerator::ForSingularBytes(
Context<FieldDescriptor> field) {
return std::make_unique<SingularBytes>();
}}},
R"cc(
$hazzer$;
::google::protobuf::rust_internal::PtrAndLen $getter_thunk$($QualifiedMsg$* msg) {
absl::string_view val = msg->$field$();
return google::protobuf::rust_internal::PtrAndLen(val.data(), val.size());
}
void $setter_thunk$($QualifiedMsg$* msg, const char* ptr, ::std::size_t size) {
msg->set_$field$(absl::string_view(ptr, size));
}
void $clearer_thunk$($QualifiedMsg$* msg) { msg->clear_$field$(); }
)cc");
}
} // namespace rust
} // namespace compiler
} // namespace protobuf

@ -29,53 +29,42 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "absl/strings/string_view.h"
#include "google/protobuf/compiler/rust/accessors/accessors.h"
#include "google/protobuf/compiler/rust/accessors/accessor_generator.h"
#include "google/protobuf/compiler/rust/context.h"
#include "google/protobuf/compiler/rust/naming.h"
#include "google/protobuf/descriptor.h"
namespace google {
namespace protobuf {
namespace compiler {
namespace rust {
namespace {
class SingularMessage final : public AccessorGenerator {
public:
~SingularMessage() override = default;
void InMsgImpl(Context<FieldDescriptor> field) const override {
field.Emit(
{
{"field", field.desc().name()},
},
R"rs(
void SingularMessage::InMsgImpl(Context<FieldDescriptor> field) const {
field.Emit(
{
{"field", field.desc().name()},
},
R"rs(
// inMsgImpl
pub fn r#$field$(&self) -> $Msg$View {
$Msg$View { msg: self.msg, _phantom: std::marker::PhantomData }
}
)rs");
}
}
void InExternC(Context<FieldDescriptor> field) const override {
field.Emit({},
R"rs(
void SingularMessage::InExternC(Context<FieldDescriptor> field) const {
field.Emit({},
R"rs(
// inExternC
)rs");
}
void InThunkCc(Context<FieldDescriptor> field) const override {
field.Emit({},
R"cc(
// inThunkCC
)cc");
}
};
} // namespace
}
std::unique_ptr<AccessorGenerator> AccessorGenerator::ForSingularMessage(
Context<FieldDescriptor> field) {
return std::make_unique<SingularMessage>();
void SingularMessage::InThunkCc(Context<FieldDescriptor> field) const {
field.Emit({},
R"cc(
// inThunkCC
)cc");
}
} // namespace rust
} // namespace compiler
} // namespace protobuf

@ -28,11 +28,9 @@
// (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 <memory>
#include "absl/strings/string_view.h"
#include "google/protobuf/compiler/cpp/helpers.h"
#include "google/protobuf/compiler/rust/accessors/accessors.h"
#include "google/protobuf/compiler/rust/accessors/accessor_generator.h"
#include "google/protobuf/compiler/rust/context.h"
#include "google/protobuf/compiler/rust/naming.h"
#include "google/protobuf/descriptor.h"
@ -41,30 +39,26 @@ namespace google {
namespace protobuf {
namespace compiler {
namespace rust {
namespace {
class SingularScalar final : public AccessorGenerator {
public:
~SingularScalar() override = default;
void InMsgImpl(Context<FieldDescriptor> field) const override {
field.Emit(
{
{"field", field.desc().name()},
{"Scalar", PrimitiveRsTypeName(field)},
{"hazzer_thunk", Thunk(field, "has")},
{"getter",
[&] {
field.Emit({}, R"rs(
void SingularScalar::InMsgImpl(Context<FieldDescriptor> field) const {
field.Emit(
{
{"field", field.desc().name()},
{"Scalar", PrimitiveRsTypeName(field)},
{"hazzer_thunk", Thunk(field, "has")},
{"getter",
[&] {
field.Emit({}, R"rs(
pub fn r#$field$(&self) -> $Scalar$ {
unsafe { $getter_thunk$(self.msg) }
}
)rs");
}},
{"getter_opt",
[&] {
if (!field.desc().is_optional()) return;
if (!field.desc().has_presence()) return;
field.Emit({}, R"rs(
}},
{"getter_opt",
[&] {
if (!field.desc().is_optional()) return;
if (!field.desc().has_presence()) return;
field.Emit({}, R"rs(
pub fn r#$field$_opt(&self) -> Option<$Scalar$> {
if !unsafe { $hazzer_thunk$(self.msg) } {
return None;
@ -72,12 +66,12 @@ class SingularScalar final : public AccessorGenerator {
Some(unsafe { $getter_thunk$(self.msg) })
}
)rs");
}},
{"getter_thunk", Thunk(field, "get")},
{"setter_thunk", Thunk(field, "set")},
{"clearer_thunk", Thunk(field, "clear")},
},
R"rs(
}},
{"getter_thunk", Thunk(field, "get")},
{"setter_thunk", Thunk(field, "set")},
{"clearer_thunk", Thunk(field, "clear")},
},
R"rs(
$getter$
$getter_opt$
@ -88,65 +82,59 @@ class SingularScalar final : public AccessorGenerator {
}
}
)rs");
}
}
void InExternC(Context<FieldDescriptor> field) const override {
field.Emit(
{{"Scalar", PrimitiveRsTypeName(field)},
{"hazzer_thunk", Thunk(field, "has")},
{"getter_thunk", Thunk(field, "get")},
{"setter_thunk", Thunk(field, "set")},
{"clearer_thunk", Thunk(field, "clear")},
{"hazzer",
[&] {
if (field.desc().has_presence()) {
field.Emit(
R"rs(fn $hazzer_thunk$(raw_msg: $pbi$::RawMessage) -> bool;)rs");
}
}}},
R"rs(
void SingularScalar::InExternC(Context<FieldDescriptor> field) const {
field.Emit(
{{"Scalar", PrimitiveRsTypeName(field)},
{"hazzer_thunk", Thunk(field, "has")},
{"getter_thunk", Thunk(field, "get")},
{"setter_thunk", Thunk(field, "set")},
{"clearer_thunk", Thunk(field, "clear")},
{"hazzer",
[&] {
if (field.desc().has_presence()) {
field.Emit(
R"rs(fn $hazzer_thunk$(raw_msg: $pbi$::RawMessage) -> bool;)rs");
}
}}},
R"rs(
$hazzer$
fn $getter_thunk$(raw_msg: $pbi$::RawMessage) -> $Scalar$;
fn $setter_thunk$(raw_msg: $pbi$::RawMessage, val: $Scalar$);
fn $clearer_thunk$(raw_msg: $pbi$::RawMessage);
)rs");
}
}
void InThunkCc(Context<FieldDescriptor> field) const override {
field.Emit({{"field", cpp::FieldName(&field.desc())},
{"Scalar", cpp::PrimitiveTypeName(field.desc().cpp_type())},
{"QualifiedMsg",
cpp::QualifiedClassName(field.desc().containing_type())},
{"hazzer_thunk", Thunk(field, "has")},
{"getter_thunk", Thunk(field, "get")},
{"setter_thunk", Thunk(field, "set")},
{"clearer_thunk", Thunk(field, "clear")},
{"hazzer",
[&] {
if (field.desc().has_presence()) {
field.Emit(R"cc(
bool $hazzer_thunk$($QualifiedMsg$* msg) {
return msg->has_$field$();
}
)cc");
}
}}},
R"cc(
$hazzer$;
$Scalar$ $getter_thunk$($QualifiedMsg$* msg) { return msg->$field$(); }
void $setter_thunk$($QualifiedMsg$* msg, $Scalar$ val) {
msg->set_$field$(val);
void SingularScalar::InThunkCc(Context<FieldDescriptor> field) const {
field.Emit({{"field", cpp::FieldName(&field.desc())},
{"Scalar", cpp::PrimitiveTypeName(field.desc().cpp_type())},
{"QualifiedMsg",
cpp::QualifiedClassName(field.desc().containing_type())},
{"hazzer_thunk", Thunk(field, "has")},
{"getter_thunk", Thunk(field, "get")},
{"setter_thunk", Thunk(field, "set")},
{"clearer_thunk", Thunk(field, "clear")},
{"hazzer",
[&] {
if (field.desc().has_presence()) {
field.Emit(R"cc(
bool $hazzer_thunk$($QualifiedMsg$* msg) {
return msg->has_$field$();
}
)cc");
}
void $clearer_thunk$($QualifiedMsg$* msg) { msg->clear_$field$(); }
)cc");
}
};
} // namespace
std::unique_ptr<AccessorGenerator> AccessorGenerator::ForSingularScalar(
Context<FieldDescriptor> field) {
return std::make_unique<SingularScalar>();
}}},
R"cc(
$hazzer$;
$Scalar$ $getter_thunk$($QualifiedMsg$* msg) { return msg->$field$(); }
void $setter_thunk$($QualifiedMsg$* msg, $Scalar$ val) {
msg->set_$field$(val);
}
void $clearer_thunk$($QualifiedMsg$* msg) { msg->clear_$field$(); }
)cc");
}
} // namespace rust
} // namespace compiler
} // namespace protobuf

@ -0,0 +1,51 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2023 Google LLC. 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 LLC. 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 "absl/strings/string_view.h"
#include "google/protobuf/compiler/rust/accessors/accessor_generator.h"
#include "google/protobuf/compiler/rust/context.h"
#include "google/protobuf/descriptor.h"
namespace google {
namespace protobuf {
namespace compiler {
namespace rust {
void UnsupportedField::InMsgImpl(Context<FieldDescriptor> field) const {
field.Emit(R"rs(
// Unsupported! :(
)rs");
field.printer().PrintRaw("\n");
}
} // namespace rust
} // namespace compiler
} // namespace protobuf
} // namespace google

@ -289,8 +289,7 @@ bool RustGenerator::Generate(const FileDescriptor* file_desc,
for (int i = 0; i < file.desc().message_type_count(); ++i) {
auto msg = file.WithDesc(file.desc().message_type(i));
MessageGenerator gen(msg);
gen.GenerateRs(msg);
GenerateRs(msg);
msg.printer().PrintRaw("\n");
if (file.is_cpp()) {
@ -299,7 +298,7 @@ bool RustGenerator::Generate(const FileDescriptor* file_desc,
thunks_msg.Emit({{"Msg", msg.desc().full_name()}}, R"cc(
// $Msg$
)cc");
gen.GenerateThunksCc(thunks_msg);
GenerateThunksCc(thunks_msg);
thunks_msg.printer().PrintRaw("\n");
}
}

@ -205,18 +205,7 @@ void MessageDrop(Context<Descriptor> msg) {
}
} // namespace
MessageGenerator::MessageGenerator(Context<Descriptor> msg) {
accessors_.resize(msg.desc().field_count());
for (int i = 0; i < msg.desc().field_count(); ++i) {
auto field = msg.WithDesc(msg.desc().field(i));
accessors_[i] = AccessorGenerator::For(field);
if (accessors_[i] == nullptr) {
ABSL_LOG(WARNING) << "unsupported field: " << field.desc().full_name();
}
}
}
void MessageGenerator::GenerateRs(Context<Descriptor> msg) {
void GenerateRs(Context<Descriptor> msg) {
if (msg.desc().map_key() != nullptr) {
ABSL_LOG(WARNING) << "unsupported map field: " << msg.desc().full_name();
return;
@ -233,31 +222,19 @@ void MessageGenerator::GenerateRs(Context<Descriptor> msg) {
{"accessor_fns",
[&] {
for (int i = 0; i < msg.desc().field_count(); ++i) {
auto& gen = accessors_[i];
auto field = msg.WithDesc(*msg.desc().field(i));
msg.Emit({{"comment", FieldInfoComment(field)}}, R"rs(
// $comment$
)rs");
if (gen == nullptr) {
msg.Emit({{"field", field.desc().full_name()}}, R"rs(
// Unsupported! :(
)rs");
msg.printer().PrintRaw("\n");
continue;
}
gen->GenerateMsgImpl(field);
GenerateAccessorMsgImpl(field);
msg.printer().PrintRaw("\n");
}
}},
{"accessor_externs",
[&] {
for (int i = 0; i < msg.desc().field_count(); ++i) {
auto& gen = accessors_[i];
if (gen == nullptr) continue;
gen->GenerateExternC(msg.WithDesc(*msg.desc().field(i)));
GenerateAccessorExternC(msg.WithDesc(*msg.desc().field(i)));
msg.printer().PrintRaw("\n");
}
}},
@ -273,8 +250,7 @@ void MessageGenerator::GenerateRs(Context<Descriptor> msg) {
++i) {
auto nested_msg =
msg.WithDesc(msg.desc().nested_type(i));
MessageGenerator gen(nested_msg);
gen.GenerateRs(nested_msg);
GenerateRs(nested_msg);
}
}}},
R"rs(
@ -398,7 +374,7 @@ void MessageGenerator::GenerateRs(Context<Descriptor> msg) {
}
// Generates code for a particular message in `.pb.thunk.cc`.
void MessageGenerator::GenerateThunksCc(Context<Descriptor> msg) {
void GenerateThunksCc(Context<Descriptor> msg) {
ABSL_CHECK(msg.is_cpp());
if (msg.desc().map_key() != nullptr) {
ABSL_LOG(WARNING) << "unsupported map field: " << msg.desc().full_name();
@ -419,17 +395,13 @@ void MessageGenerator::GenerateThunksCc(Context<Descriptor> msg) {
for (int i = 0; i < msg.desc().nested_type_count(); ++i) {
Context<Descriptor> nested_msg =
msg.WithDesc(msg.desc().nested_type(i));
MessageGenerator gen(nested_msg);
gen.GenerateThunksCc(nested_msg);
GenerateThunksCc(nested_msg);
}
}},
{"accessor_thunks",
[&] {
for (int i = 0; i < msg.desc().field_count(); ++i) {
auto& gen = accessors_[i];
if (gen == nullptr) continue;
gen->GenerateThunkCc(msg.WithDesc(*msg.desc().field(i)));
GenerateAccessorThunkCc(msg.WithDesc(*msg.desc().field(i)));
}
}},
},

@ -43,19 +43,11 @@ namespace protobuf {
namespace compiler {
namespace rust {
class MessageGenerator final {
public:
explicit MessageGenerator(Context<Descriptor> msg);
// Generates code for a particular message in `.pb.rs`.
void GenerateRs(Context<Descriptor> msg);
// Generates code for a particular message in `.pb.rs`.
void GenerateRs(Context<Descriptor> msg);
// Generates code for a particular message in `.pb.thunk.cc`.
void GenerateThunksCc(Context<Descriptor> msg);
private:
std::vector<std::unique_ptr<AccessorGenerator>> accessors_;
};
// Generates code for a particular message in `.pb.thunk.cc`.
void GenerateThunksCc(Context<Descriptor> msg);
} // namespace rust
} // namespace compiler

Loading…
Cancel
Save