Deduplicate vtables for mutators

This also includes some misc. cleanup in singular_string with affected lines.

PiperOrigin-RevId: 601515263
pull/15516/head
Alyssa Haroldsen 1 year ago committed by Copybara-Service
parent c13512aee3
commit 022730e43c
  1. 95
      src/google/protobuf/compiler/rust/accessors/singular_scalar.cc
  2. 83
      src/google/protobuf/compiler/rust/accessors/singular_string.cc
  3. 4
      src/google/protobuf/compiler/rust/naming.cc
  4. 3
      src/google/protobuf/compiler/rust/naming.h

@ -32,7 +32,7 @@ void SingularScalar::InMsgImpl(Context& ctx, const FieldDescriptor& field,
{"default_value", DefaultValue(ctx, field)},
{"getter",
[&] {
ctx.Emit({}, R"rs(
ctx.Emit(R"rs(
pub fn $field$($view_self$) -> $Scalar$ {
unsafe { $getter_thunk$(self.raw_msg()) }
}
@ -42,7 +42,7 @@ void SingularScalar::InMsgImpl(Context& ctx, const FieldDescriptor& field,
[&] {
if (!field.is_optional()) return;
if (!field.has_presence()) return;
ctx.Emit({}, R"rs(
ctx.Emit(R"rs(
pub fn $field$_opt($view_self$) -> $pb$::Optional<$Scalar$> {
if !unsafe { $hazzer_thunk$(self.raw_msg()) } {
return $pb$::Optional::Unset($default_value$);
@ -55,59 +55,71 @@ void SingularScalar::InMsgImpl(Context& ctx, const FieldDescriptor& field,
{"getter_thunk", ThunkName(ctx, field, "get")},
{"setter_thunk", ThunkName(ctx, field, "set")},
{"clearer_thunk", ThunkName(ctx, field, "clear")},
{"vtable_name", VTableName(field)},
{"vtable",
[&] {
if (accessor_case != AccessorCase::OWNED) {
return;
}
if (field.has_presence()) {
ctx.Emit(R"rs(
const $vtable_name$: &'static $pbi$::PrimitiveOptionalMutVTable<$Scalar$> =
&$pbi$::PrimitiveOptionalMutVTable::new(
$pbi$::Private,
$getter_thunk$,
$setter_thunk$,
$clearer_thunk$,
$default_value$,
);
)rs");
} else {
ctx.Emit(R"rs(
const $vtable_name$: &'static $pbi$::PrimitiveVTable<$Scalar$> =
&$pbi$::PrimitiveVTable::new(
$pbi$::Private,
$getter_thunk$,
$setter_thunk$,
);
)rs");
}
}},
{"getter_mut",
[&] {
if (accessor_case == AccessorCase::VIEW) {
return;
}
if (field.has_presence()) {
ctx.Emit({}, R"rs(
ctx.Emit(R"rs(
pub fn $field$_mut(&mut self) -> $pb$::FieldEntry<'_, $Scalar$> {
static VTABLE: $pbi$::PrimitiveOptionalMutVTable<$Scalar$> =
$pbi$::PrimitiveOptionalMutVTable::new(
unsafe {
let has = $hazzer_thunk$(self.raw_msg());
$pbi$::new_vtable_field_entry::<$Scalar$>(
$pbi$::Private,
$getter_thunk$,
$setter_thunk$,
$clearer_thunk$,
$default_value$,
);
unsafe {
let has = $hazzer_thunk$(self.raw_msg());
$pbi$::new_vtable_field_entry::<$Scalar$>(
$pbi$::Private,
self.as_mutator_message_ref(),
&VTABLE,
has,
)
}
self.as_mutator_message_ref(),
$Msg$::$vtable_name$,
has,
)
}
}
)rs");
} else {
ctx.Emit({}, R"rs(
ctx.Emit(R"rs(
pub fn $field$_mut(&mut self) -> $pb$::Mut<'_, $Scalar$> {
static VTABLE: $pbi$::PrimitiveVTable<$Scalar$> =
$pbi$::PrimitiveVTable::new(
// SAFETY:
// - The message is valid for the output lifetime.
// - The vtable is valid for the field.
// - There is no way to mutate the element for the output
// lifetime except through this mutator.
unsafe {
$pb$::PrimitiveMut::from_inner(
$pbi$::Private,
$getter_thunk$,
$setter_thunk$,
);
// SAFETY:
// - The message is valid for the output lifetime.
// - The vtable is valid for the field.
// - There is no way to mutate the element for the output
// lifetime except through this mutator.
unsafe {
$pb$::PrimitiveMut::from_inner(
$pbi$::RawVTableMutator::new(
$pbi$::Private,
$pbi$::RawVTableMutator::new(
$pbi$::Private,
self.as_mutator_message_ref(),
&VTABLE,
),
)
}
self.as_mutator_message_ref(),
$Msg$::$vtable_name$,
),
)
}
}
)rs");
}
@ -116,6 +128,7 @@ void SingularScalar::InMsgImpl(Context& ctx, const FieldDescriptor& field,
R"rs(
$getter$
$getter_opt$
$vtable$
$getter_mut$
)rs");
}

@ -5,8 +5,6 @@
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
#include <string>
#include "absl/strings/string_view.h"
#include "google/protobuf/compiler/cpp/helpers.h"
#include "google/protobuf/compiler/rust/accessors/accessor_case.h"
@ -42,6 +40,18 @@ void SingularString::InMsgImpl(Context& ctx, const FieldDescriptor& field,
ctx.Emit("view");
}
}},
{"transform_field_entry",
[&] {
if (field.type() == FieldDescriptor::TYPE_STRING) {
ctx.Emit(R"rs(
$pb$::ProtoStrMut::field_entry_from_bytes(
$pbi$::Private, out
)
)rs");
} else {
ctx.Emit("out");
}
}},
{"view_lifetime", ViewLifetime(accessor_case)},
{"view_self", ViewReceiver(accessor_case)},
{"field_optional_getter",
@ -58,45 +68,51 @@ void SingularString::InMsgImpl(Context& ctx, const FieldDescriptor& field,
}
)rs");
}},
{"vtable_name", VTableName(field)},
{"vtable",
[&] {
if (accessor_case != AccessorCase::OWNED) {
return;
}
if (field.has_presence()) {
ctx.Emit({{"default_value", DefaultValue(ctx, field)}},
R"rs(
// SAFETY: for `string` fields, the default value is verified as valid UTF-8
const $vtable_name$: &'static $pbi$::BytesOptionalMutVTable = &unsafe {
$pbi$::BytesOptionalMutVTable::new(
$pbi$::Private,
$getter_thunk$,
$setter_thunk$,
$clearer_thunk$,
$default_value$,
)
};
)rs");
} else {
ctx.Emit(R"rs(
const $vtable_name$: &'static $pbi$::BytesMutVTable =
&$pbi$::BytesMutVTable::new(
$pbi$::Private,
$getter_thunk$,
$setter_thunk$,
);
)rs");
}
}},
{"field_mutator_getter",
[&] {
if (accessor_case == AccessorCase::VIEW) {
return;
}
if (field.has_presence()) {
ctx.Emit(
{
{"default_val", DefaultValue(ctx, field)},
{"transform_field_entry",
[&] {
if (field.type() == FieldDescriptor::TYPE_STRING) {
ctx.Emit(R"rs(
$pb$::ProtoStrMut::field_entry_from_bytes(
$pbi$::Private, out
)
)rs");
} else {
ctx.Emit("out");
}
}},
},
R"rs(
ctx.Emit(R"rs(
pub fn $field$_mut(&mut self) -> $pb$::FieldEntry<'_, $proxied_type$> {
static VTABLE: $pbi$::BytesOptionalMutVTable = unsafe {
$pbi$::BytesOptionalMutVTable::new(
$pbi$::Private,
$getter_thunk$,
$setter_thunk$,
$clearer_thunk$,
$default_val$,
)
};
let out = unsafe {
let has = $hazzer_thunk$(self.raw_msg());
$pbi$::new_vtable_field_entry(
$pbi$::Private,
self.as_mutator_message_ref(),
&VTABLE,
$Msg$::$vtable_name$,
has,
)
};
@ -106,19 +122,13 @@ void SingularString::InMsgImpl(Context& ctx, const FieldDescriptor& field,
} else {
ctx.Emit(R"rs(
pub fn $field$_mut(&mut self) -> $pb$::Mut<'_, $proxied_type$> {
static VTABLE: $pbi$::BytesMutVTable =
$pbi$::BytesMutVTable::new(
$pbi$::Private,
$getter_thunk$,
$setter_thunk$,
);
unsafe {
<$pb$::Mut<$proxied_type$>>::from_inner(
$pbi$::Private,
$pbi$::RawVTableMutator::new(
$pbi$::Private,
self.as_mutator_message_ref(),
&VTABLE,
$Msg$::$vtable_name$,
)
)
}
@ -134,6 +144,7 @@ void SingularString::InMsgImpl(Context& ctx, const FieldDescriptor& field,
}
$field_optional_getter$
$vtable$
$field_mutator_getter$
)rs");
}

@ -167,6 +167,10 @@ std::string ThunkName(Context& ctx, const Descriptor& msg,
op);
}
std::string VTableName(const FieldDescriptor& field) {
return absl::StrCat("__", absl::AsciiStrToUpper(field.name()), "_VTABLE");
}
std::string GetFullyQualifiedPath(Context& ctx, const Descriptor& msg) {
auto rel_path = GetCrateRelativeQualifiedPath(ctx, msg);
if (IsInCurrentlyGeneratingCrate(ctx, msg)) {

@ -34,6 +34,9 @@ std::string ThunkName(Context& ctx, const OneofDescriptor& field,
std::string ThunkName(Context& ctx, const Descriptor& msg,
absl::string_view op);
// Returns the local constant that defines the vtable for mutating `field`.
std::string VTableName(const FieldDescriptor& field);
// Returns an absolute path to the Proxied Rust type of the given field.
// The absolute path is guaranteed to work in the crate that defines the field.
// It may be crate-relative, or directly reference the owning crate of the type.

Loading…
Cancel
Save