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 12 months ago committed by Copybara-Service
parent ec1fd2700e
commit b9ad33cdff
  1. 78
      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,69 +223,42 @@ 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(
$pbi$::Private,
$getter_thunk$,
$setter_thunk$,
);
unsafe {
<$pb$::Mut<$RsType$>>::from_inner(
$pbi$::Private,
$pbi$::RawVTableMutator::new(
$pbi$::Private,
self.inner,
&VTABLE,
)
)
}
}
)rs");
}
}}},
R"rs(
pub fn r#$field$(&self) -> $pb$::View<'_, $RsType$> {
let s = unsafe { $getter_thunk$($self$).as_ref() };
unsafe { __pb::ProtoStr::from_utf8_unchecked(s).into() }
}
$maybe_mutator$
)rs");
} else {
ctx.Emit({{"field", fieldName}, ctx.Emit({{"field", fieldName},
{"getter_thunk", getter_thunk}, {"getter_thunk", getter_thunk},
{"setter_thunk", setter_thunk}, {"setter_thunk", setter_thunk},
{"clearer_thunk", clearer_thunk}, {"clearer_thunk", clearer_thunk},
{"self", self}, {"self", self},
{"RsType", rsType}, {"RsType", rsType},
{"as_ref", asRef},
{"vtable", vtable},
{"optional_type_args", optionalTypeArgs},
{"string_transform", stringTransform},
{"maybe_mutator", {"maybe_mutator",
[&] { [&] {
// TODO: once the rust public api is accessible, // TODO: check mutational pathway genn'd correctly
// by tooling, ensure that this only appears for the if (is_mut) {
// mutational pathway
if (is_mut && fieldType) {
ctx.Emit({}, R"rs( ctx.Emit({}, R"rs(
pub fn r#$field$_mut(&self) -> $pb$::Mut<'_, $RsType$> { pub fn r#$field$_mut(&self) -> $pb$::Mut<'_, $RsType$> {
static VTABLE: $pbi$::PrimitiveVTable<$RsType$> = static VTABLE: $pbi$::$vtable$$optional_type_args$ =
$pbi$::PrimitiveVTable::new( $pbi$::$vtable$::new(
$pbi$::Private, $pbi$::Private,
$getter_thunk$, $getter_thunk$,
$setter_thunk$); $setter_thunk$);
unsafe { unsafe {
$pb$::PrimitiveMut::from_inner( <$pb$::Mut<$RsType$>>::from_inner(
$pbi$::Private, $pbi$::Private,
$pbi$::RawVTableMutator::new( $pbi$::RawVTableMutator::new(
$pbi$::Private, $pbi$::Private,
@ -295,13 +273,13 @@ void GetterForViewOrMut(Context& ctx, const FieldDescriptor& field,
}}}, }}},
R"rs( R"rs(
pub fn r#$field$(&self) -> $pb$::View<'_, $RsType$> { pub fn r#$field$(&self) -> $pb$::View<'_, $RsType$> {
unsafe { $getter_thunk$($self$) } 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) {
for (int i = 0; i < msg.field_count(); ++i) { for (int i = 0; i < msg.field_count(); ++i) {

Loading…
Cancel
Save