Skip to content

Commit

Permalink
Reify our unifying dreams
Browse files Browse the repository at this point in the history
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
  • Loading branch information
honglooker authored and copybara-github committed Dec 19, 2023
1 parent ec1fd27 commit b9ad33c
Showing 1 changed file with 58 additions and 80 deletions.
138 changes: 58 additions & 80 deletions src/google/protobuf/compiler/rust/message.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include "absl/log/absl_check.h"
#include "absl/log/absl_log.h"
#include "absl/strings/str_format.h"
#include "absl/strings/string_view.h"
#include "google/protobuf/compiler/cpp/helpers.h"
#include "google/protobuf/compiler/cpp/names.h"
Expand Down Expand Up @@ -163,6 +164,10 @@ void MessageDrop(Context& ctx, const Descriptor& msg) {
)rs");
}

bool IsStringOrBytes(FieldDescriptor::Type t) {
return t == FieldDescriptor::TYPE_STRING || t == FieldDescriptor::TYPE_BYTES;
}

void GetterForViewOrMut(Context& ctx, const FieldDescriptor& field,
bool is_mut) {
auto fieldName = field.name();
Expand Down Expand Up @@ -218,89 +223,62 @@ void GetterForViewOrMut(Context& ctx, const FieldDescriptor& field,
}

auto rsType = PrimitiveRsTypeName(field);
if (fieldType == FieldDescriptor::TYPE_STRING ||
fieldType == FieldDescriptor::TYPE_BYTES) {
ctx.Emit({{"field", fieldName},
{"self", self},
{"getter_thunk", getter_thunk},
{"setter_thunk", setter_thunk},
{"RsType", rsType},
{"maybe_mutator",
[&] {
if (is_mut) {
ctx.Emit({}, R"rs(
pub fn r#$field$_mut(&self) -> $pb$::Mut<'_, $RsType$> {
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},
{"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(
auto asRef = IsStringOrBytes(fieldType) ? ".as_ref()" : "";
auto vtable =
IsStringOrBytes(fieldType) ? "BytesMutVTable" : "PrimitiveVTable";
// PrimitiveVtable is parameterized based on the underlying primitive, like
// u32 so we need to provide this additional type arg
auto optionalTypeArgs =
IsStringOrBytes(fieldType) ? "" : absl::StrFormat("<%s>", rsType);
// need to stuff ProtoStr and [u8] behind a reference since they are DSTs
auto stringTransform =
IsStringOrBytes(fieldType)
? "unsafe { __pb::ProtoStr::from_utf8_unchecked(res).into() }"
: "res";

ctx.Emit({{"field", fieldName},
{"getter_thunk", getter_thunk},
{"setter_thunk", setter_thunk},
{"clearer_thunk", clearer_thunk},
{"self", self},
{"RsType", rsType},
{"as_ref", asRef},
{"vtable", vtable},
{"optional_type_args", optionalTypeArgs},
{"string_transform", stringTransform},
{"maybe_mutator",
[&] {
// 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$ =
$pbi$::$vtable$::new(
$pbi$::Private,
$getter_thunk$,
$setter_thunk$);
unsafe {
<$pb$::Mut<$RsType$>>::from_inner(
$pbi$::Private,
$pbi$::RawVTableMutator::new(
$pbi$::Private,
$pbi$::RawVTableMutator::new(
$pbi$::Private,
self.inner,
&VTABLE
),
)
}
self.inner,
&VTABLE
),
)
}
)rs");
}
}}},
R"rs(
pub fn r#$field$(&self) -> $pb$::View<'_, $RsType$> {
unsafe { $getter_thunk$($self$) }
}
}
)rs");
}
}}},
R"rs(
pub fn r#$field$(&self) -> $pb$::View<'_, $RsType$> {
let res = unsafe { $getter_thunk$($self$)$as_ref$ };
$string_transform$
}
$maybe_mutator$
)rs");
}
$maybe_mutator$
)rs");
}

void AccessorsForViewOrMut(Context& ctx, const Descriptor& msg, bool is_mut) {
Expand Down

0 comments on commit b9ad33c

Please sign in to comment.