Reify our unifying dreams

This CL collapses (strings, bytes) into primitives for message.cc::GetterForViewOrMut.

Strings, bytes, and all primitives have been unified, properly parameterized based on RsType.
Returning $pb$::Mut<$RsType$> and $pb$::View<$RsType$> made this possible.

Note that the vtables for primitives take in an additional type arg, so we've added that.
In addition, strings / bytes (aka stringlikes) require a transform, so that'll be invoked on an as-needed basis.

PiperOrigin-RevId: 592328216
pull/15085/head
Hong Shin 11 months ago committed by Copybara-Service
parent ec1fd2700e
commit b9ad33cdff
  1. 138
      src/google/protobuf/compiler/rust/message.cc

@ -9,6 +9,7 @@
#include "absl/log/absl_check.h" #include "absl/log/absl_check.h"
#include "absl/log/absl_log.h" #include "absl/log/absl_log.h"
#include "absl/strings/str_format.h"
#include "absl/strings/string_view.h" #include "absl/strings/string_view.h"
#include "google/protobuf/compiler/cpp/helpers.h" #include "google/protobuf/compiler/cpp/helpers.h"
#include "google/protobuf/compiler/cpp/names.h" #include "google/protobuf/compiler/cpp/names.h"
@ -163,6 +164,10 @@ void MessageDrop(Context& ctx, const Descriptor& msg) {
)rs"); )rs");
} }
bool IsStringOrBytes(FieldDescriptor::Type t) {
return t == FieldDescriptor::TYPE_STRING || t == FieldDescriptor::TYPE_BYTES;
}
void GetterForViewOrMut(Context& ctx, const FieldDescriptor& field, void GetterForViewOrMut(Context& ctx, const FieldDescriptor& field,
bool is_mut) { bool is_mut) {
auto fieldName = field.name(); auto fieldName = field.name();
@ -218,89 +223,62 @@ void GetterForViewOrMut(Context& ctx, const FieldDescriptor& field,
} }
auto rsType = PrimitiveRsTypeName(field); auto rsType = PrimitiveRsTypeName(field);
if (fieldType == FieldDescriptor::TYPE_STRING || auto asRef = IsStringOrBytes(fieldType) ? ".as_ref()" : "";
fieldType == FieldDescriptor::TYPE_BYTES) { auto vtable =
ctx.Emit({{"field", fieldName}, IsStringOrBytes(fieldType) ? "BytesMutVTable" : "PrimitiveVTable";
{"self", self}, // PrimitiveVtable is parameterized based on the underlying primitive, like
{"getter_thunk", getter_thunk}, // u32 so we need to provide this additional type arg
{"setter_thunk", setter_thunk}, auto optionalTypeArgs =
{"RsType", rsType}, IsStringOrBytes(fieldType) ? "" : absl::StrFormat("<%s>", rsType);
{"maybe_mutator", // need to stuff ProtoStr and [u8] behind a reference since they are DSTs
[&] { auto stringTransform =
if (is_mut) { IsStringOrBytes(fieldType)
ctx.Emit({}, R"rs( ? "unsafe { __pb::ProtoStr::from_utf8_unchecked(res).into() }"
pub fn r#$field$_mut(&self) -> $pb$::Mut<'_, $RsType$> { : "res";
static VTABLE: $pbi$::BytesMutVTable =
$pbi$::BytesMutVTable::new( ctx.Emit({{"field", fieldName},
$pbi$::Private, {"getter_thunk", getter_thunk},
$getter_thunk$, {"setter_thunk", setter_thunk},
$setter_thunk$, {"clearer_thunk", clearer_thunk},
); {"self", self},
{"RsType", rsType},
unsafe { {"as_ref", asRef},
<$pb$::Mut<$RsType$>>::from_inner( {"vtable", vtable},
$pbi$::Private, {"optional_type_args", optionalTypeArgs},
$pbi$::RawVTableMutator::new( {"string_transform", stringTransform},
$pbi$::Private, {"maybe_mutator",
self.inner, [&] {
&VTABLE, // TODO: check mutational pathway genn'd correctly
) if (is_mut) {
) ctx.Emit({}, R"rs(
} pub fn r#$field$_mut(&self) -> $pb$::Mut<'_, $RsType$> {
} static VTABLE: $pbi$::$vtable$$optional_type_args$ =
)rs"); $pbi$::$vtable$::new(
} $pbi$::Private,
}}}, $getter_thunk$,
R"rs( $setter_thunk$);
pub fn r#$field$(&self) -> $pb$::View<'_, $RsType$> { unsafe {
let s = unsafe { $getter_thunk$($self$).as_ref() }; <$pb$::Mut<$RsType$>>::from_inner(
unsafe { __pb::ProtoStr::from_utf8_unchecked(s).into() } $pbi$::Private,
} $pbi$::RawVTableMutator::new(
$maybe_mutator$
)rs");
} else {
ctx.Emit({{"field", fieldName},
{"getter_thunk", getter_thunk},
{"setter_thunk", setter_thunk},
{"clearer_thunk", clearer_thunk},
{"self", self},
{"RsType", rsType},
{"maybe_mutator",
[&] {
// TODO: once the rust public api is accessible,
// by tooling, ensure that this only appears for the
// mutational pathway
if (is_mut && fieldType) {
ctx.Emit({}, R"rs(
pub fn r#$field$_mut(&self) -> $pb$::Mut<'_, $RsType$> {
static VTABLE: $pbi$::PrimitiveVTable<$RsType$> =
$pbi$::PrimitiveVTable::new(
$pbi$::Private,
$getter_thunk$,
$setter_thunk$);
unsafe {
$pb$::PrimitiveMut::from_inner(
$pbi$::Private, $pbi$::Private,
$pbi$::RawVTableMutator::new( self.inner,
$pbi$::Private, &VTABLE
self.inner, ),
&VTABLE )
),
)
}
} }
)rs"); }
} )rs");
}}}, }
R"rs( }}},
pub fn r#$field$(&self) -> $pb$::View<'_, $RsType$> { R"rs(
unsafe { $getter_thunk$($self$) } pub fn r#$field$(&self) -> $pb$::View<'_, $RsType$> {
} let res = unsafe { $getter_thunk$($self$)$as_ref$ };
$string_transform$
}
$maybe_mutator$ $maybe_mutator$
)rs"); )rs");
}
} }
void AccessorsForViewOrMut(Context& ctx, const Descriptor& msg, bool is_mut) { void AccessorsForViewOrMut(Context& ctx, const Descriptor& msg, bool is_mut) {

Loading…
Cancel
Save