diff --git a/src/google/protobuf/compiler/rust/accessors/singular_scalar.cc b/src/google/protobuf/compiler/rust/accessors/singular_scalar.cc index 5301fbc41b..c905c253c6 100644 --- a/src/google/protobuf/compiler/rust/accessors/singular_scalar.cc +++ b/src/google/protobuf/compiler/rust/accessors/singular_scalar.cc @@ -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"); } diff --git a/src/google/protobuf/compiler/rust/accessors/singular_string.cc b/src/google/protobuf/compiler/rust/accessors/singular_string.cc index 40b4609c9d..9b2a1026c1 100644 --- a/src/google/protobuf/compiler/rust/accessors/singular_string.cc +++ b/src/google/protobuf/compiler/rust/accessors/singular_string.cc @@ -5,8 +5,6 @@ // license that can be found in the LICENSE file or at // https://developers.google.com/open-source/licenses/bsd -#include - #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"); } diff --git a/src/google/protobuf/compiler/rust/naming.cc b/src/google/protobuf/compiler/rust/naming.cc index 10eb6b162b..571a63ec1e 100644 --- a/src/google/protobuf/compiler/rust/naming.cc +++ b/src/google/protobuf/compiler/rust/naming.cc @@ -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)) { diff --git a/src/google/protobuf/compiler/rust/naming.h b/src/google/protobuf/compiler/rust/naming.h index b4cd263c4e..b683a9306e 100644 --- a/src/google/protobuf/compiler/rust/naming.h +++ b/src/google/protobuf/compiler/rust/naming.h @@ -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.