Refactor the with-presence accessor geneartion (hasser, get_opt and clearer) into helper functions.

This unifies the duplicated logic that we had for each different non-repeated field to emit these same 3 methods for each of the different field types, and moves the has/clear off of upb-accessors-C-codegen and onto the upb-C-API for all cases (matching the singular scalars case which moved in a previous change).

PiperOrigin-RevId: 667953223
pull/17944/head
Protobuf Team Bot 3 months ago committed by Copybara-Service
parent 182699f8fd
commit 336c9c324c
  1. 1
      src/google/protobuf/compiler/rust/BUILD.bazel
  2. 2
      src/google/protobuf/compiler/rust/accessors/BUILD.bazel
  3. 1
      src/google/protobuf/compiler/rust/accessors/accessors.cc
  4. 65
      src/google/protobuf/compiler/rust/accessors/singular_cord.cc
  5. 158
      src/google/protobuf/compiler/rust/accessors/singular_message.cc
  6. 106
      src/google/protobuf/compiler/rust/accessors/singular_scalar.cc
  7. 129
      src/google/protobuf/compiler/rust/accessors/singular_string.cc
  8. 134
      src/google/protobuf/compiler/rust/accessors/with_presence.cc
  9. 28
      src/google/protobuf/compiler/rust/accessors/with_presence.h
  10. 34
      src/google/protobuf/compiler/rust/naming.cc
  11. 9
      src/google/protobuf/compiler/rust/naming.h

@ -178,6 +178,7 @@ cc_library(
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/log:absl_log",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/strings:str_format",
],
)

@ -18,12 +18,14 @@ cc_library(
"singular_scalar.cc",
"singular_string.cc",
"unsupported_field.cc",
"with_presence.cc",
],
hdrs = [
"accessor_case.h",
"accessors.h",
"default_value.h",
"generator.h",
"with_presence.h",
],
copts = COPTS,
strip_include_prefix = "/src",

@ -65,6 +65,7 @@ std::unique_ptr<AccessorGenerator> AccessorGeneratorFor(
}
ABSL_LOG(FATAL) << "Unexpected field type: " << field.type();
return nullptr;
}
} // namespace

@ -11,6 +11,7 @@
#include "google/protobuf/compiler/cpp/helpers.h"
#include "google/protobuf/compiler/rust/accessors/accessor_case.h"
#include "google/protobuf/compiler/rust/accessors/generator.h"
#include "google/protobuf/compiler/rust/accessors/with_presence.h"
#include "google/protobuf/compiler/rust/context.h"
#include "google/protobuf/compiler/rust/naming.h"
#include "google/protobuf/descriptor.h"
@ -22,17 +23,19 @@ namespace rust {
void SingularCord::InMsgImpl(Context& ctx, const FieldDescriptor& field,
AccessorCase accessor_case) const {
if (field.has_presence()) {
WithPresenceAccessorsInMsgImpl(ctx, field, accessor_case);
}
std::string field_name = FieldNameWithCollisionAvoidance(field);
bool is_string_type = field.type() == FieldDescriptor::TYPE_STRING;
ctx.Emit(
{{"field", RsSafeName(field_name)},
{"raw_field_name", field_name},
{"hazzer_thunk", ThunkName(ctx, field, "has")},
{"borrowed_getter_thunk", ThunkName(ctx, field, "get_cord_borrowed")},
{"owned_getter_thunk", ThunkName(ctx, field, "get_cord_owned")},
{"is_flat_thunk", ThunkName(ctx, field, "cord_is_flat")},
{"setter_thunk", ThunkName(ctx, field, "set")},
{"clearer_thunk", ThunkName(ctx, field, "clear")},
{"getter_thunk", ThunkName(ctx, field, "get")},
{"proxied_type", RsTypePath(ctx, field)},
{"borrowed_type",
@ -159,36 +162,20 @@ void SingularCord::InMsgImpl(Context& ctx, const FieldDescriptor& field,
$setter_impl$
}
)rs");
}},
{"hazzer",
[&] {
if (!field.has_presence()) return;
ctx.Emit({}, R"rs(
pub fn has_$raw_field_name$($view_self$) -> bool {
unsafe { $hazzer_thunk$(self.raw_msg()) }
})rs");
}},
{"clearer",
[&] {
if (accessor_case == AccessorCase::VIEW) return;
if (!field.has_presence()) return;
ctx.Emit({}, R"rs(
pub fn clear_$raw_field_name$(&mut self) {
unsafe { $clearer_thunk$(self.raw_msg()) }
})rs");
}}},
R"rs(
$getter$
$setter$
$hazzer$
$clearer$
)rs");
}
void SingularCord::InExternC(Context& ctx, const FieldDescriptor& field) const {
if (field.has_presence()) {
WithPresenceAccessorsInExternC(ctx, field);
}
ctx.Emit(
{{"hazzer_thunk", ThunkName(ctx, field, "has")},
{"borrowed_getter_thunk", ThunkName(ctx, field, "get_cord_borrowed")},
{{"borrowed_getter_thunk", ThunkName(ctx, field, "get_cord_borrowed")},
{"owned_getter_thunk", ThunkName(ctx, field, "get_cord_owned")},
{"is_flat_thunk", ThunkName(ctx, field, "cord_is_flat")},
{"getter_thunk", ThunkName(ctx, field, "get")},
@ -205,7 +192,6 @@ void SingularCord::InExternC(Context& ctx, const FieldDescriptor& field) const {
)rs");
}
}},
{"clearer_thunk", ThunkName(ctx, field, "clear")},
{"getter_thunks",
[&] {
if (ctx.is_cpp()) {
@ -219,47 +205,26 @@ void SingularCord::InExternC(Context& ctx, const FieldDescriptor& field) const {
fn $getter_thunk$(raw_msg: $pbr$::RawMessage) -> $pbr$::PtrAndLen;
)rs");
}
}},
{"with_presence_fields_thunks",
[&] {
if (field.has_presence()) {
ctx.Emit(R"rs(
fn $hazzer_thunk$(raw_msg: $pbr$::RawMessage) -> bool;
fn $clearer_thunk$(raw_msg: $pbr$::RawMessage);
)rs");
}
}}},
R"rs(
$with_presence_fields_thunks$
$getter_thunks$
$setter$
)rs");
}
void SingularCord::InThunkCc(Context& ctx, const FieldDescriptor& field) const {
if (field.has_presence()) {
WithPresenceAccessorsInThunkCc(ctx, field);
}
ctx.Emit(
{{"field", cpp::FieldName(&field)},
{"QualifiedMsg", cpp::QualifiedClassName(field.containing_type())},
{"hazzer_thunk", ThunkName(ctx, field, "has")},
{"setter_thunk", ThunkName(ctx, field, "set")},
{"clearer_thunk", ThunkName(ctx, field, "clear")},
{"borrowed_getter_thunk", ThunkName(ctx, field, "get_cord_borrowed")},
{"owned_getter_thunk", ThunkName(ctx, field, "get_cord_owned")},
{"is_flat_thunk", ThunkName(ctx, field, "cord_is_flat")},
{"with_presence_fields_thunks",
[&] {
if (field.has_presence()) {
ctx.Emit(R"cc(
bool $hazzer_thunk$($QualifiedMsg$* msg) {
return msg->has_$field$();
}
void $clearer_thunk$($QualifiedMsg$* msg) { msg->clear_$field$(); }
)cc");
}
}}},
{"is_flat_thunk", ThunkName(ctx, field, "cord_is_flat")}},
R"cc(
$with_presence_fields_thunks$;
bool $is_flat_thunk$($QualifiedMsg$* msg) {
const absl::Cord& cord = msg->$field$();
return cord.TryFlat().has_value();

@ -11,6 +11,7 @@
#include "google/protobuf/compiler/cpp/helpers.h"
#include "google/protobuf/compiler/rust/accessors/accessor_case.h"
#include "google/protobuf/compiler/rust/accessors/generator.h"
#include "google/protobuf/compiler/rust/accessors/with_presence.h"
#include "google/protobuf/compiler/rust/context.h"
#include "google/protobuf/compiler/rust/naming.h"
#include "google/protobuf/descriptor.h"
@ -22,24 +23,28 @@ namespace rust {
void SingularMessage::InMsgImpl(Context& ctx, const FieldDescriptor& field,
AccessorCase accessor_case) const {
if (field.has_presence()) {
WithPresenceAccessorsInMsgImpl(ctx, field, accessor_case);
}
// fully qualified message name with modules prefixed
std::string msg_type = RsTypePath(ctx, field);
std::string field_name = FieldNameWithCollisionAvoidance(field);
ctx.Emit({{"msg_type", msg_type},
{"field", RsSafeName(field_name)},
{"raw_field_name", field_name},
{"view_lifetime", ViewLifetime(accessor_case)},
{"view_self", ViewReceiver(accessor_case)},
{"getter_thunk", ThunkName(ctx, field, "get")},
{"getter_mut_thunk", ThunkName(ctx, field, "get_mut")},
{"clearer_thunk", ThunkName(ctx, field, "clear")},
{"hazzer_thunk", ThunkName(ctx, field, "has")},
{"set_allocated_thunk", ThunkName(ctx, field, "set")},
{
"getter_body",
[&] {
if (ctx.is_upb()) {
ctx.Emit({}, R"rs(
ctx.Emit(
{
{"msg_type", msg_type},
{"field", RsSafeName(field_name)},
{"raw_field_name", field_name},
{"view_lifetime", ViewLifetime(accessor_case)},
{"view_self", ViewReceiver(accessor_case)},
{"getter_thunk", ThunkName(ctx, field, "get")},
{"getter_mut_thunk", ThunkName(ctx, field, "get_mut")},
{"set_allocated_thunk", ThunkName(ctx, field, "set")},
{
"getter_body",
[&] {
if (ctx.is_upb()) {
ctx.Emit({}, R"rs(
let submsg = unsafe { $getter_thunk$(self.raw_msg()) };
//~ For upb, getters return null if the field is unset, so we need
//~ to check for null and return the default instance manually.
@ -50,68 +55,58 @@ void SingularMessage::InMsgImpl(Context& ctx, const FieldDescriptor& field,
Some(field) => $msg_type$View::new($pbi$::Private, field),
}
)rs");
} else {
ctx.Emit({}, R"rs(
} else {
ctx.Emit({}, R"rs(
//~ For C++ kernel, getters automatically return the
//~ default_instance if the field is unset.
let submsg = unsafe { $getter_thunk$(self.raw_msg()) };
$msg_type$View::new($pbi$::Private, submsg)
)rs");
}
},
},
{"getter",
[&] {
ctx.Emit({}, R"rs(
}
},
},
{"getter",
[&] {
ctx.Emit({}, R"rs(
pub fn $field$($view_self$) -> $msg_type$View<$view_lifetime$> {
$getter_body$
}
)rs");
}},
{"getter_mut_body",
[&] {
if (ctx.is_cpp()) {
ctx.Emit({}, R"rs(
}},
{"getter_mut_body",
[&] {
if (ctx.is_cpp()) {
ctx.Emit({}, R"rs(
let raw_msg = unsafe { $getter_mut_thunk$(self.raw_msg()) };
$msg_type$Mut::from_parent($pbi$::Private,
self.as_mutator_message_ref($pbi$::Private), raw_msg)
)rs");
} else {
ctx.Emit({}, R"rs(
let raw_msg = unsafe {
} else {
ctx.Emit({}, R"rs(
let raw_msg = unsafe {
$getter_mut_thunk$(self.raw_msg(), self.arena().raw())
};
$msg_type$Mut::from_parent($pbi$::Private,
self.as_mutator_message_ref($pbi$::Private), raw_msg)
)rs");
}
}},
{"getter_mut",
[&] {
if (accessor_case == AccessorCase::VIEW) {
return;
}
}
}},
{"getter_mut",
[&] {
if (accessor_case == AccessorCase::VIEW) {
return;
}
ctx.Emit({}, R"rs(
ctx.Emit({}, R"rs(
pub fn $raw_field_name$_mut(&mut self) -> $msg_type$Mut<'_> {
$getter_mut_body$
})rs");
}},
{"getter_opt",
[&] {
}},
{"setter_body",
[&] {
if (accessor_case == AccessorCase::VIEW) return;
if (ctx.is_upb()) {
ctx.Emit({}, R"rs(
pub fn $raw_field_name$_opt($view_self$) ->
$pb$::Optional<$msg_type$View<$view_lifetime$>> {
let view = self.$field$();
$pb$::Optional::new(view, self.has_$raw_field_name$())
}
)rs");
}},
{"setter_body",
[&] {
if (accessor_case == AccessorCase::VIEW) return;
if (ctx.is_upb()) {
ctx.Emit({}, R"rs(
// The message and arena are dropped after the setter. The
// memory remains allocated as we fuse the arena with the
// parent message's arena.
@ -125,8 +120,8 @@ void SingularMessage::InMsgImpl(Context& ctx, const FieldDescriptor& field,
msg.as_mutator_message_ref($pbi$::Private).msg());
}
)rs");
} else {
ctx.Emit({}, R"rs(
} else {
ctx.Emit({}, R"rs(
// Prevent the memory from being deallocated. The setter
// transfers ownership of the memory to the parent message.
let mut msg = std::mem::ManuallyDrop::new(val.into_proxied($pbi$::Private));
@ -135,52 +130,37 @@ void SingularMessage::InMsgImpl(Context& ctx, const FieldDescriptor& field,
msg.as_mutator_message_ref($pbi$::Private).msg());
}
)rs");
}
}},
{"setter",
[&] {
if (accessor_case == AccessorCase::VIEW) return;
ctx.Emit(R"rs(
}
}},
{"setter",
[&] {
if (accessor_case == AccessorCase::VIEW) return;
ctx.Emit(R"rs(
pub fn set_$raw_field_name$(&mut self,
val: impl $pb$::IntoProxied<$msg_type$>) {
$setter_body$
}
)rs");
}},
{"hazzer",
[&] {
ctx.Emit({}, R"rs(
pub fn has_$raw_field_name$($view_self$) -> bool {
unsafe { $hazzer_thunk$(self.raw_msg()) }
})rs");
}},
{"clearer",
[&] {
if (accessor_case == AccessorCase::VIEW) return;
ctx.Emit({}, R"rs(
pub fn clear_$raw_field_name$(&mut self) {
unsafe { $clearer_thunk$(self.raw_msg()) }
})rs");
}}},
R"rs(
}},
},
R"rs(
$getter$
$getter_mut$
$getter_opt$
$setter$
$hazzer$
$clearer$
)rs");
}
void SingularMessage::InExternC(Context& ctx,
const FieldDescriptor& field) const {
if (field.has_presence()) {
WithPresenceAccessorsInExternC(ctx, field);
}
ctx.Emit(
{
{"getter_thunk", ThunkName(ctx, field, "get")},
{"getter_mut_thunk", ThunkName(ctx, field, "get_mut")},
{"clearer_thunk", ThunkName(ctx, field, "clear")},
{"hazzer_thunk", ThunkName(ctx, field, "has")},
{"set_allocated_thunk", ThunkName(ctx, field, "set")},
{"getter_mut",
[&] {
@ -211,8 +191,6 @@ void SingularMessage::InExternC(Context& ctx,
R"rs(
fn $getter_thunk$(raw_msg: $pbr$::RawMessage) -> $ReturnType$;
$getter_mut$
fn $clearer_thunk$(raw_msg: $pbr$::RawMessage);
fn $hazzer_thunk$(raw_msg: $pbr$::RawMessage) -> bool;
fn $set_allocated_thunk$(raw_msg: $pbr$::RawMessage,
field_msg: $pbr$::RawMessage);
)rs");
@ -220,13 +198,15 @@ void SingularMessage::InExternC(Context& ctx,
void SingularMessage::InThunkCc(Context& ctx,
const FieldDescriptor& field) const {
if (field.has_presence()) {
WithPresenceAccessorsInThunkCc(ctx, field);
}
ctx.Emit({{"QualifiedMsg", cpp::QualifiedClassName(field.containing_type())},
{"FieldMsg", cpp::QualifiedClassName(field.message_type())},
{"set_allocated_thunk", ThunkName(ctx, field, "set")},
{"getter_thunk", ThunkName(ctx, field, "get")},
{"getter_mut_thunk", ThunkName(ctx, field, "get_mut")},
{"clearer_thunk", ThunkName(ctx, field, "clear")},
{"hazzer_thunk", ThunkName(ctx, field, "has")},
{"field", cpp::FieldName(&field)}},
R"cc(
const void* $getter_thunk$($QualifiedMsg$* msg) {
@ -235,8 +215,6 @@ void SingularMessage::InThunkCc(Context& ctx,
void* $getter_mut_thunk$($QualifiedMsg$* msg) {
return static_cast<void*>(msg->mutable_$field$());
}
void $clearer_thunk$($QualifiedMsg$* msg) { msg->clear_$field$(); }
bool $hazzer_thunk$($QualifiedMsg$* msg) { return msg->has_$field$(); }
void $set_allocated_thunk$($QualifiedMsg$* msg, $FieldMsg$* sub_msg) {
msg->set_allocated_$field$(sub_msg);
}

@ -13,6 +13,7 @@
#include "google/protobuf/compiler/rust/accessors/accessor_case.h"
#include "google/protobuf/compiler/rust/accessors/default_value.h"
#include "google/protobuf/compiler/rust/accessors/generator.h"
#include "google/protobuf/compiler/rust/accessors/with_presence.h"
#include "google/protobuf/compiler/rust/context.h"
#include "google/protobuf/compiler/rust/naming.h"
#include "google/protobuf/compiler/rust/upb_helpers.h"
@ -58,6 +59,10 @@ std::string UpbCTypeNameForFunctions(const FieldDescriptor& field) {
void SingularScalar::InMsgImpl(Context& ctx, const FieldDescriptor& field,
AccessorCase accessor_case) const {
if (field.has_presence()) {
WithPresenceAccessorsInMsgImpl(ctx, field, accessor_case);
}
std::string field_name = FieldNameWithCollisionAvoidance(field);
ctx.Emit(
@ -100,19 +105,6 @@ void SingularScalar::InMsgImpl(Context& ctx, const FieldDescriptor& field,
)rs");
}
}},
{"getter_opt",
[&] {
if (!field.has_presence()) return;
ctx.Emit(R"rs(
pub fn $raw_field_name$_opt($view_self$) -> $pb$::Optional<$Scalar$> {
if self.has_$raw_field_name$() {
$pb$::Optional::Set(self.$field$())
} else {
$pb$::Optional::Unset($default_value$)
}
}
)rs");
}},
{"setter",
[&] {
if (accessor_case == AccessorCase::VIEW) return;
@ -140,65 +132,24 @@ void SingularScalar::InMsgImpl(Context& ctx, const FieldDescriptor& field,
)rs");
}
}},
{"hazzer",
[&] {
if (!field.has_presence()) return;
if (ctx.is_cpp()) {
ctx.Emit(R"rs(
pub fn has_$raw_field_name$($view_self$) -> bool {
unsafe { $hazzer_thunk$(self.raw_msg()) }
})rs");
} else {
ctx.Emit(R"rs(
pub fn has_$raw_field_name$($view_self$) -> bool {
unsafe {
let mt = <Self as $pbr$::AssociatedMiniTable>::mini_table();
let f = $pbr$::upb_MiniTable_GetFieldByIndex(
mt, $upb_mt_field_index$);
$pbr$::upb_Message_HasBaseField(self.raw_msg(), f)
}
})rs");
}
}},
{"clearer",
[&] {
if (accessor_case == AccessorCase::VIEW) return;
if (!field.has_presence()) return;
if (ctx.is_cpp()) {
ctx.Emit(R"rs(
pub fn clear_$raw_field_name$(&mut self) {
unsafe { $clearer_thunk$(self.raw_msg()) }
})rs");
} else {
ctx.Emit(R"rs(
pub fn clear_$raw_field_name$(&mut self) {
unsafe {
let mt = <Self as $pbr$::AssociatedMiniTable>::mini_table();
let f = $pbr$::upb_MiniTable_GetFieldByIndex(
mt, $upb_mt_field_index$);
$pbr$::upb_Message_ClearBaseField(self.raw_msg(), f);
}
})rs");
}
}},
{"getter_thunk", ThunkName(ctx, field, "get")},
{"setter_thunk", ThunkName(ctx, field, "set")},
{"clearer_thunk", ThunkName(ctx, field, "clear")},
},
R"rs(
$getter$
$getter_opt$
$setter$
$hazzer$
$clearer$
)rs");
}
void SingularScalar::InExternC(Context& ctx,
const FieldDescriptor& field) const {
// Only cpp kernel uses thunks.
// Only cpp kernel uses thunks for singular scalars.
if (ctx.is_upb()) return;
if (field.has_presence()) {
WithPresenceAccessorsInExternC(ctx, field);
}
// In order to soundly pass a Rust type to C/C++ as a function argument,
// the types must be FFI-compatible.
// This requires special consideration for enums, which aren't trivial
@ -207,21 +158,9 @@ void SingularScalar::InExternC(Context& ctx,
// Upb defines enum thunks as taking `int32_t`, and so we can pass Rust enums
// directly to thunks without any cast.
ctx.Emit({{"Scalar", RsTypePath(ctx, field)},
{"hazzer_thunk", ThunkName(ctx, field, "has")},
{"getter_thunk", ThunkName(ctx, field, "get")},
{"setter_thunk", ThunkName(ctx, field, "set")},
{"clearer_thunk", ThunkName(ctx, field, "clear")},
{"with_presence_fields_thunks",
[&] {
if (field.has_presence()) {
ctx.Emit(R"rs(
fn $hazzer_thunk$(raw_msg: $pbr$::RawMessage) -> bool;
fn $clearer_thunk$(raw_msg: $pbr$::RawMessage);
)rs");
}
}}},
{"setter_thunk", ThunkName(ctx, field, "set")}},
R"rs(
$with_presence_fields_thunks$
fn $getter_thunk$(raw_msg: $pbr$::RawMessage) -> $Scalar$;
fn $setter_thunk$(raw_msg: $pbr$::RawMessage, val: $Scalar$);
)rs");
@ -229,6 +168,10 @@ void SingularScalar::InExternC(Context& ctx,
void SingularScalar::InThunkCc(Context& ctx,
const FieldDescriptor& field) const {
if (field.has_presence()) {
WithPresenceAccessorsInThunkCc(ctx, field);
}
std::string scalar;
auto enum_ = field.enum_type();
if (enum_ != nullptr) {
@ -245,23 +188,12 @@ void SingularScalar::InThunkCc(Context& ctx,
ctx.Emit({{"field", cpp::FieldName(&field)},
{"Scalar", scalar},
{"QualifiedMsg", cpp::QualifiedClassName(field.containing_type())},
{"hazzer_thunk", ThunkName(ctx, field, "has")},
{"getter_thunk", ThunkName(ctx, field, "get")},
{"setter_thunk", ThunkName(ctx, field, "set")},
{"clearer_thunk", ThunkName(ctx, field, "clear")},
{"with_presence_fields_thunks",
[&] {
if (!field.has_presence()) return;
ctx.Emit(R"cc(
bool $hazzer_thunk$($QualifiedMsg$* msg) {
return msg->has_$field$();
}
void $clearer_thunk$($QualifiedMsg$* msg) { msg->clear_$field$(); }
)cc");
}}},
{"setter_thunk", ThunkName(ctx, field, "set")}},
R"cc(
$with_presence_fields_thunks$;
$Scalar$ $getter_thunk$($QualifiedMsg$* msg) { return msg->$field$(); }
$Scalar$ $getter_thunk$($QualifiedMsg$* msg) {
return msg->$field$();
}
void $setter_thunk$($QualifiedMsg$* msg, $Scalar$ val) {
msg->set_$field$(val);
}

@ -11,6 +11,7 @@
#include "google/protobuf/compiler/cpp/helpers.h"
#include "google/protobuf/compiler/rust/accessors/accessor_case.h"
#include "google/protobuf/compiler/rust/accessors/generator.h"
#include "google/protobuf/compiler/rust/accessors/with_presence.h"
#include "google/protobuf/compiler/rust/context.h"
#include "google/protobuf/compiler/rust/naming.h"
#include "google/protobuf/descriptor.h"
@ -22,15 +23,17 @@ namespace rust {
void SingularString::InMsgImpl(Context& ctx, const FieldDescriptor& field,
AccessorCase accessor_case) const {
if (field.has_presence()) {
WithPresenceAccessorsInMsgImpl(ctx, field, accessor_case);
}
std::string field_name = FieldNameWithCollisionAvoidance(field);
ctx.Emit(
{
{"field", RsSafeName(field_name)},
{"raw_field_name", field_name},
{"hazzer_thunk", ThunkName(ctx, field, "has")},
{"getter_thunk", ThunkName(ctx, field, "get")},
{"setter_thunk", ThunkName(ctx, field, "set")},
{"clearer_thunk", ThunkName(ctx, field, "clear")},
{"proxied_type", RsTypePath(ctx, field)},
io::Printer::Sub("transform_view",
[&] {
@ -54,18 +57,6 @@ void SingularString::InMsgImpl(Context& ctx, const FieldDescriptor& field,
$transform_view$
})rs");
}},
{"getter_opt",
[&] {
if (!field.has_presence()) return;
ctx.Emit(R"rs(
pub fn $raw_field_name$_opt($view_self$) -> $pb$::Optional<$pb$::View<$view_lifetime$, $proxied_type$>> {
$pb$::Optional::new(
self.$field$(),
self.has_$raw_field_name$()
)
}
)rs");
}},
{"setter_impl",
[&] {
if (ctx.is_cpp()) {
@ -109,62 +100,37 @@ void SingularString::InMsgImpl(Context& ctx, const FieldDescriptor& field,
}
)rs");
}},
{"hazzer",
[&] {
if (!field.has_presence()) return;
ctx.Emit({}, R"rs(
pub fn has_$raw_field_name$($view_self$) -> bool {
unsafe { $hazzer_thunk$(self.raw_msg()) }
})rs");
}},
{"clearer",
[&] {
if (accessor_case == AccessorCase::VIEW) return;
if (!field.has_presence()) return;
ctx.Emit({}, R"rs(
pub fn clear_$raw_field_name$(&mut self) {
unsafe { $clearer_thunk$(self.raw_msg()) }
})rs");
}},
},
R"rs(
$getter$
$getter_opt$
$setter$
$hazzer$
$clearer$
)rs");
}
void SingularString::InExternC(Context& ctx,
const FieldDescriptor& field) const {
ctx.Emit({{"hazzer_thunk", ThunkName(ctx, field, "has")},
{"getter_thunk", ThunkName(ctx, field, "get")},
{"setter_thunk", ThunkName(ctx, field, "set")},
{"setter",
[&] {
if (ctx.is_cpp()) {
ctx.Emit(R"rs(
if (field.has_presence()) {
WithPresenceAccessorsInExternC(ctx, field);
}
ctx.Emit(
{
{"getter_thunk", ThunkName(ctx, field, "get")},
{"setter_thunk", ThunkName(ctx, field, "set")},
{"setter",
[&] {
if (ctx.is_cpp()) {
ctx.Emit(R"rs(
fn $setter_thunk$(raw_msg: $pbr$::RawMessage, val: $pbr$::CppStdString);
)rs");
} else {
ctx.Emit(R"rs(
} else {
ctx.Emit(R"rs(
fn $setter_thunk$(raw_msg: $pbr$::RawMessage, val: $pbr$::PtrAndLen);
)rs");
}
}},
{"clearer_thunk", ThunkName(ctx, field, "clear")},
{"with_presence_fields_thunks",
[&] {
if (field.has_presence()) {
ctx.Emit(R"rs(
fn $hazzer_thunk$(raw_msg: $pbr$::RawMessage) -> bool;
fn $clearer_thunk$(raw_msg: $pbr$::RawMessage);
)rs");
}
}}},
R"rs(
$with_presence_fields_thunks$
}
}},
},
R"rs(
fn $getter_thunk$(raw_msg: $pbr$::RawMessage) -> $pbr$::PtrAndLen;
$setter$
)rs");
@ -172,34 +138,27 @@ void SingularString::InExternC(Context& ctx,
void SingularString::InThunkCc(Context& ctx,
const FieldDescriptor& field) const {
ctx.Emit({{"field", cpp::FieldName(&field)},
{"QualifiedMsg", cpp::QualifiedClassName(field.containing_type())},
{"hazzer_thunk", ThunkName(ctx, field, "has")},
{"getter_thunk", ThunkName(ctx, field, "get")},
{"setter_thunk", ThunkName(ctx, field, "set")},
{"clearer_thunk", ThunkName(ctx, field, "clear")},
{"with_presence_fields_thunks",
[&] {
if (field.has_presence()) {
ctx.Emit(R"cc(
bool $hazzer_thunk$($QualifiedMsg$* msg) {
return msg->has_$field$();
}
void $clearer_thunk$($QualifiedMsg$* msg) { msg->clear_$field$(); }
)cc");
}
}}},
R"cc(
$with_presence_fields_thunks$;
::google::protobuf::rust::PtrAndLen $getter_thunk$($QualifiedMsg$* msg) {
absl::string_view val = msg->$field$();
return ::google::protobuf::rust::PtrAndLen(val.data(), val.size());
}
void $setter_thunk$($QualifiedMsg$* msg, std::string* s) {
msg->set_$field$(std::move(*s));
delete s;
}
)cc");
if (field.has_presence()) {
WithPresenceAccessorsInThunkCc(ctx, field);
}
ctx.Emit(
{
{"field", cpp::FieldName(&field)},
{"QualifiedMsg", cpp::QualifiedClassName(field.containing_type())},
{"getter_thunk", ThunkName(ctx, field, "get")},
{"setter_thunk", ThunkName(ctx, field, "set")},
},
R"cc(
::google::protobuf::rust::PtrAndLen $getter_thunk$($QualifiedMsg$* msg) {
absl::string_view val = msg->$field$();
return ::google::protobuf::rust::PtrAndLen(val.data(), val.size());
}
void $setter_thunk$($QualifiedMsg$* msg, std::string* s) {
msg->set_$field$(std::move(*s));
delete s;
}
)cc");
}
} // namespace rust

@ -0,0 +1,134 @@
#include "google/protobuf/compiler/rust/accessors/with_presence.h"
#include <string>
#include "absl/log/absl_check.h"
#include "google/protobuf/compiler/cpp/helpers.h"
#include "google/protobuf/compiler/rust/accessors/accessor_case.h"
#include "google/protobuf/compiler/rust/context.h"
#include "google/protobuf/compiler/rust/naming.h"
#include "google/protobuf/compiler/rust/upb_helpers.h"
#include "google/protobuf/descriptor.h"
namespace google {
namespace protobuf {
namespace compiler {
namespace rust {
void WithPresenceAccessorsInMsgImpl(Context& ctx, const FieldDescriptor& field,
AccessorCase accessor_case) {
ABSL_CHECK(field.has_presence());
std::string field_name = FieldNameWithCollisionAvoidance(field);
ctx.Emit(
{{"field", RsSafeName(field_name)},
{"raw_field_name", field_name}, // Never r# prefixed
{"view_type", RsViewType(ctx, field, ViewLifetime(accessor_case))},
{"view_self", ViewReceiver(accessor_case)},
{"hazzer",
[&] {
if (ctx.is_cpp()) {
ctx.Emit({{"hazzer_thunk", ThunkName(ctx, field, "has")}},
R"rs(
pub fn has_$raw_field_name$($view_self$) -> bool {
unsafe {
$hazzer_thunk$(self.raw_msg())
}
}
)rs");
} else {
ctx.Emit({{"upb_mt_field_index", UpbMiniTableFieldIndex(field)}},
R"rs(
pub fn has_$raw_field_name$($view_self$) -> bool {
unsafe {
let f = $pbr$::upb_MiniTable_GetFieldByIndex(
<Self as $pbr$::AssociatedMiniTable>::mini_table(),
$upb_mt_field_index$);
$pbr$::upb_Message_HasBaseField(self.raw_msg(), f)
}
}
)rs");
}
}},
{"clearer",
[&] {
if (accessor_case == AccessorCase::VIEW) return;
if (ctx.is_cpp()) {
ctx.Emit({{"clearer_thunk", ThunkName(ctx, field, "clear")}},
R"rs(
pub fn clear_$raw_field_name$(&mut self) {
unsafe { $clearer_thunk$(self.raw_msg()) }
})rs");
} else {
ctx.Emit({{"upb_mt_field_index", UpbMiniTableFieldIndex(field)}},
R"rs(
pub fn clear_$raw_field_name$(&mut self) {
unsafe {
let mt = <Self as $pbr$::AssociatedMiniTable>::mini_table();
let f = $pbr$::upb_MiniTable_GetFieldByIndex(
mt, $upb_mt_field_index$);
$pbr$::upb_Message_ClearBaseField(self.raw_msg(), f);
}
})rs");
}
}},
{"opt_getter",
[&] {
// Cord fields don't support the _opt getter.
if (field.options().ctype() == FieldOptions::CORD) return;
ctx.Emit(
R"rs(
pub fn $raw_field_name$_opt($view_self$) -> $pb$::Optional<$view_type$> {
$pb$::Optional::new(self.$field$(), self.has_$raw_field_name$())
}
)rs");
}}},
R"rs(
$hazzer$
$clearer$
$opt_getter$
)rs");
}
void WithPresenceAccessorsInExternC(Context& ctx,
const FieldDescriptor& field) {
ABSL_CHECK(field.has_presence());
if (ctx.is_upb()) return;
ctx.Emit(
{
{"hazzer_thunk", ThunkName(ctx, field, "has")},
{"clearer_thunk", ThunkName(ctx, field, "clear")},
},
R"rs(
fn $hazzer_thunk$(raw_msg: $pbr$::RawMessage) -> bool;
fn $clearer_thunk$(raw_msg: $pbr$::RawMessage);
)rs");
}
void WithPresenceAccessorsInThunkCc(Context& ctx,
const FieldDescriptor& field) {
ABSL_CHECK(ctx.is_cpp());
ABSL_CHECK(field.has_presence());
ctx.Emit(
{
{"field", cpp::FieldName(&field)},
{"QualifiedMsg", cpp::QualifiedClassName(field.containing_type())},
{"hazzer_thunk", ThunkName(ctx, field, "has")},
{"clearer_thunk", ThunkName(ctx, field, "clear")},
},
R"rs(
bool $hazzer_thunk$($QualifiedMsg$* msg) {
return msg->has_$field$();
}
void $clearer_thunk$($QualifiedMsg$* msg) { msg->clear_$field$(); }
)rs");
}
} // namespace rust
} // namespace compiler
} // namespace protobuf
} // namespace google

@ -0,0 +1,28 @@
#ifndef GOOGLE_PROTOBUF_COMPILER_RUST_ACCESSORS_WITH_PRESENCE_H__
#define GOOGLE_PROTOBUF_COMPILER_RUST_ACCESSORS_WITH_PRESENCE_H__
#include "google/protobuf/compiler/rust/accessors/accessor_case.h"
#include "google/protobuf/compiler/rust/context.h"
#include "google/protobuf/descriptor.h"
// Helper functions for generating the common accessors that any with-presence
// field have (the hassers, clearers, and the Optional<> getter).
namespace google {
namespace protobuf {
namespace compiler {
namespace rust {
void WithPresenceAccessorsInMsgImpl(Context& ctx, const FieldDescriptor& field,
AccessorCase accessor_case);
void WithPresenceAccessorsInExternC(Context& ctx, const FieldDescriptor& field);
void WithPresenceAccessorsInThunkCc(Context& ctx, const FieldDescriptor& field);
} // namespace rust
} // namespace compiler
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_COMPILER_RUST_ACCESSORS_WITH_PRESENCE_H__

@ -16,6 +16,7 @@
#include "absl/strings/ascii.h"
#include "absl/strings/match.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
#include "absl/strings/str_join.h"
#include "absl/strings/str_replace.h"
#include "absl/strings/string_view.h"
@ -211,6 +212,39 @@ std::string RsTypePath(Context& ctx, const FieldDescriptor& field) {
return GetFullyQualifiedPath(ctx, *field.enum_type());
}
ABSL_LOG(FATAL) << "Unsupported field type: " << field.type_name();
return "";
}
std::string RsViewType(Context& ctx, const FieldDescriptor& field,
absl::string_view lifetime) {
switch (GetRustFieldType(field)) {
case RustFieldType::BOOL:
case RustFieldType::INT32:
case RustFieldType::INT64:
case RustFieldType::UINT32:
case RustFieldType::UINT64:
case RustFieldType::FLOAT:
case RustFieldType::DOUBLE:
case RustFieldType::ENUM:
// The View type of all scalars and enums can be spelled as the type
// itself.
return RsTypePath(ctx, field);
case RustFieldType::BYTES:
return absl::StrFormat("&%s [u8]", lifetime);
case RustFieldType::STRING:
return absl::StrFormat("&%s ::__pb::ProtoStr", lifetime);
case RustFieldType::MESSAGE:
if (lifetime.empty()) {
return absl::StrFormat(
"%sView", GetFullyQualifiedPath(ctx, *field.message_type()));
} else {
return absl::StrFormat(
"%sView<%s>", GetFullyQualifiedPath(ctx, *field.message_type()),
lifetime);
}
}
ABSL_LOG(FATAL) << "Unsupported field type: " << field.type_name();
return "";
}
std::string RustModuleForContainingType(Context& ctx,

@ -43,6 +43,15 @@ std::string RawMapThunk(Context& ctx, const EnumDescriptor& desc,
// It may be crate-relative, or directly reference the owning crate of the type.
std::string RsTypePath(Context& ctx, const FieldDescriptor& field);
// Returns the 'simple spelling' of the Rust View type for the provided field.
// For example, `i32` for int32 fields and `SomeMsgView<'$lifetime$>` for
// message fields, or `SomeMsgView` if an empty lifetime is provided).
//
// The returned type will always be functionally substitutable for the
// corresponding View<'$lifetime$, $sometype$> of the field's Rust type.
std::string RsViewType(Context& ctx, const FieldDescriptor& field,
absl::string_view lifetime);
std::string EnumRsName(const EnumDescriptor& desc);
std::string EnumValueRsName(const EnumValueDescriptor& value);

Loading…
Cancel
Save