Change upb singular scalar accessors to not use upb C accessor codegen.

PiperOrigin-RevId: 666879420
pull/17920/head
Protobuf Team Bot 6 months ago committed by Copybara-Service
parent 138451296b
commit 9f4f302f9c
  1. 10
      rust/upb/lib.rs
  2. 130
      rust/upb/message.rs
  3. 5
      rust/upb/mini_table.rs
  4. 17
      src/google/protobuf/compiler/rust/BUILD.bazel
  5. 1
      src/google/protobuf/compiler/rust/accessors/BUILD.bazel
  6. 8
      src/google/protobuf/compiler/rust/accessors/default_value.cc
  7. 8
      src/google/protobuf/compiler/rust/accessors/repeated_field.cc
  8. 141
      src/google/protobuf/compiler/rust/accessors/singular_scalar.cc
  9. 18
      src/google/protobuf/compiler/rust/message.cc
  10. 40
      src/google/protobuf/compiler/rust/upb_helpers.cc
  11. 32
      src/google/protobuf/compiler/rust/upb_helpers.h

@ -34,19 +34,15 @@ pub use map::{
};
mod message;
pub use message::{
upb_Message, upb_Message_Clear, upb_Message_DeepClone, upb_Message_DeepCopy,
upb_Message_IsEqual, upb_Message_MergeFrom, upb_Message_New, upb_Message_SetBaseField,
RawMessage,
};
pub use message::*;
mod message_value;
pub use message_value::{upb_MessageValue, upb_MutableMessageValue};
mod mini_table;
pub use mini_table::{
upb_MiniTable, upb_MiniTableField, upb_MiniTable_FindFieldByNumber, RawMiniTable,
RawMiniTableField,
upb_MiniTable, upb_MiniTableField, upb_MiniTable_FindFieldByNumber,
upb_MiniTable_GetFieldByIndex, RawMiniTable, RawMiniTableField,
};
mod opaque_pointee;

@ -13,17 +13,22 @@ opaque_pointee!(upb_Message);
pub type RawMessage = NonNull<upb_Message>;
extern "C" {
/// SAFETY:
/// # Safety
/// - `mini_table` and `arena` must be valid to deref
pub fn upb_Message_New(mini_table: *const upb_MiniTable, arena: RawArena)
-> Option<RawMessage>;
/// SAFETY:
/// # Safety
/// - `m` and `mini_table` must be valid to deref
/// - `mini_table` must be the MiniTable associtaed with `m`
/// - `mini_table` must be the MiniTable associated with `m`
pub fn upb_Message_Clear(m: RawMessage, mini_table: *const upb_MiniTable);
/// SAFETY:
/// # Safety
/// - `m` and `mini_table` must be valid to deref
/// - `f` must be a field associated with `f`
pub fn upb_Message_ClearBaseField(m: RawMessage, f: *const upb_MiniTableField);
/// # Safety
/// - All four arguments must be valid to deref
/// - `mini_table` must be the MiniTable associated with both `dst` and
/// `src`
@ -34,7 +39,7 @@ extern "C" {
arena: RawArena,
);
/// SAFETY:
/// # Safety
/// - All three arguments must be valid to deref
/// - `mini_table` must be the MiniTable associated with `m`
pub fn upb_Message_DeepClone(
@ -43,18 +48,86 @@ extern "C" {
arena: RawArena,
) -> Option<RawMessage>;
/// SAFETY:
/// # Safety
/// - `m` and `mini_table` must be valid to deref
/// - `f` must be a field associated with `f`
pub fn upb_Message_GetBool(
m: RawMessage,
mini_table: *const upb_MiniTableField,
default_val: bool,
) -> bool;
/// # Safety
/// - `m` and `mini_table` must be valid to deref
/// - `f` must be a field associated with `m`
pub fn upb_Message_GetInt32(
m: RawMessage,
f: *const upb_MiniTableField,
default_val: i32,
) -> i32;
/// # Safety
/// - `m` and `mini_table` must be valid to deref
/// - `f` must be a field associated with `m`
pub fn upb_Message_GetInt64(
m: RawMessage,
f: *const upb_MiniTableField,
default_val: i64,
) -> i64;
/// # Safety
/// - `m` and `mini_table` must be valid to deref
/// - `f` must be a field associated with `m`
pub fn upb_Message_GetUInt32(
m: RawMessage,
f: *const upb_MiniTableField,
default_val: u32,
) -> u32;
/// # Safety
/// - `m` and `mini_table` must be valid to deref
/// - `f` must be a field associated with `m`
pub fn upb_Message_GetUInt64(
m: RawMessage,
f: *const upb_MiniTableField,
default_val: u64,
) -> u64;
/// # Safety
/// - `m` and `mini_table` must be valid to deref
/// - `f` must be a field associated with `m`
pub fn upb_Message_GetFloat(
m: RawMessage,
f: *const upb_MiniTableField,
default_val: f32,
) -> f32;
/// # Safety
/// - `m` and `mini_table` must be valid to deref
/// - `f` must be a field associated with `m`
pub fn upb_Message_GetDouble(
m: RawMessage,
f: *const upb_MiniTableField,
default_val: f64,
) -> f64;
/// # Safety
/// - `m` and `mini_table` must be valid to deref
/// - `mini_table` must be the MiniTable associated with `m`
pub fn upb_Message_HasBaseField(m: RawMessage, mini_table: *const upb_MiniTableField) -> bool;
/// # Safety
/// - `m` and `mini_table` must be valid to deref
/// - `f` must be a field associated with `m`
/// - `val` must be a pointer to legally readable memory of the correct type
/// for the field described by `mini_table`
pub fn upb_Message_SetBaseField(
m: RawMessage,
mini_table: *const upb_MiniTableField,
f: *const upb_MiniTableField,
val: *const std::ffi::c_void,
);
/// SAFETY:
/// # Safety
/// - All four arguments must be valid to deref
/// - `mini_table` must be the MiniTable associated with both `m1` and `m2`
pub fn upb_Message_IsEqual(
@ -64,7 +137,7 @@ extern "C" {
options: i32,
) -> bool;
/// SAFETY:
/// # Safety
/// - `dst`, `src`, `mini_table` and `arena` must be valid to deref
/// - `extreg` must be valid to deref or nullptr
/// - `mini_table` must be the MiniTable associated with both `dst` and
@ -76,4 +149,43 @@ extern "C" {
extreg: *const upb_ExtensionRegistry,
arena: RawArena,
) -> bool;
/// # Safety
/// - `m` and `mini_table` must be valid to deref
/// - `f` must be a field associated with `f`
pub fn upb_Message_SetBaseFieldBool(
m: RawMessage,
mini_table: *const upb_MiniTableField,
val: bool,
);
/// # Safety
/// - `m` and `mini_table` must be valid to deref
/// - `f` must be a field associated with `m`
pub fn upb_Message_SetBaseFieldInt32(m: RawMessage, f: *const upb_MiniTableField, val: i32);
/// # Safety
/// - `m` and `mini_table` must be valid to deref
/// - `f` must be a field associated with `m`
pub fn upb_Message_SetBaseFieldInt64(m: RawMessage, f: *const upb_MiniTableField, val: i64);
/// # Safety
/// - `m` and `mini_table` must be valid to deref
/// - `f` must be a field associated with `m`
pub fn upb_Message_SetBaseFieldUInt32(m: RawMessage, f: *const upb_MiniTableField, val: u32);
/// # Safety
/// - `m` and `mini_table` must be valid to deref
/// - `f` must be a field associated with `m`
pub fn upb_Message_SetBaseFieldUInt64(m: RawMessage, f: *const upb_MiniTableField, val: u64);
/// # Safety
/// - `m` and `mini_table` must be valid to deref
/// - `f` must be a field associated with `m`
pub fn upb_Message_SetBaseFieldFloat(m: RawMessage, f: *const upb_MiniTableField, val: f32);
/// # Safety
/// - `m` and `mini_table` must be valid to deref
/// - `f` must be a field associated with `m`
pub fn upb_Message_SetBaseFieldDouble(m: RawMessage, f: *const upb_MiniTableField, val: f64);
}

@ -19,4 +19,9 @@ extern "C" {
m: *const upb_MiniTable,
number: u32,
) -> *const upb_MiniTableField;
pub fn upb_MiniTable_GetFieldByIndex(
m: *const upb_MiniTable,
number: u32,
) -> *const upb_MiniTableField;
}

@ -86,11 +86,11 @@ cc_library(
":enum",
":naming",
":oneof",
":upb_helpers",
"//src/google/protobuf",
"//src/google/protobuf/compiler/cpp:names",
"//src/google/protobuf/compiler/cpp:names_internal",
"//src/google/protobuf/compiler/rust/accessors",
"//upb_generator:mangle",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/log:absl_log",
"@com_google_absl//absl/strings",
@ -235,3 +235,18 @@ cc_library(
"@com_google_absl//absl/log:absl_log",
],
)
cc_library(
name = "upb_helpers",
srcs = ["upb_helpers.cc"],
hdrs = ["upb_helpers.h"],
strip_include_prefix = "/src",
visibility = [
"//src/google/protobuf/compiler/rust:__subpackages__",
],
deps = [
"//src/google/protobuf",
"//upb_generator:mangle",
"@com_google_absl//absl/log:absl_check",
],
)

@ -37,6 +37,7 @@ cc_library(
"//src/google/protobuf/compiler/rust:context",
"//src/google/protobuf/compiler/rust:naming",
"//src/google/protobuf/compiler/rust:rust_field_type",
"//src/google/protobuf/compiler/rust:upb_helpers",
"//src/google/protobuf/io:tokenizer",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/log:absl_log",

@ -58,13 +58,13 @@ std::string DefaultValue(Context& ctx, const FieldDescriptor& field) {
ABSL_LOG(FATAL) << "unreachable";
}
case RustFieldType::INT32:
return absl::StrFormat("%d", field.default_value_int32());
return absl::StrFormat("%di32", field.default_value_int32());
case RustFieldType::INT64:
return absl::StrFormat("%d", field.default_value_int64());
return absl::StrFormat("%di64", field.default_value_int64());
case RustFieldType::UINT64:
return absl::StrFormat("%u", field.default_value_uint64());
return absl::StrFormat("%uu64", field.default_value_uint64());
case RustFieldType::UINT32:
return absl::StrFormat("%u", field.default_value_uint32());
return absl::StrFormat("%uu32", field.default_value_uint32());
case RustFieldType::BOOL:
return absl::StrFormat("%v", field.default_value_bool());
case RustFieldType::STRING:

@ -13,6 +13,7 @@
#include "google/protobuf/compiler/rust/accessors/generator.h"
#include "google/protobuf/compiler/rust/context.h"
#include "google/protobuf/compiler/rust/naming.h"
#include "google/protobuf/compiler/rust/upb_helpers.h"
#include "google/protobuf/descriptor.h"
namespace google {
@ -110,12 +111,13 @@ void RepeatedField::InMsgImpl(Context& ctx, const FieldDescriptor& field,
return;
}
if (ctx.is_upb()) {
ctx.Emit({{"field_number", field.number()}}, R"rs(
ctx.Emit({{"field_index", UpbMiniTableFieldIndex(field)}},
R"rs(
pub fn set_$raw_field_name$(&mut self, src: impl $pb$::IntoProxied<$pb$::Repeated<$RsType$>>) {
let minitable_field = unsafe {
$pbr$::upb_MiniTable_FindFieldByNumber(
$pbr$::upb_MiniTable_GetFieldByIndex(
<Self as $pbr$::AssociatedMiniTable>::mini_table(),
$field_number$
$field_index$
)
};
let val = src.into_proxied($pbi$::Private);

@ -7,6 +7,7 @@
#include <string>
#include "absl/log/absl_check.h"
#include "absl/strings/string_view.h"
#include "google/protobuf/compiler/cpp/helpers.h"
#include "google/protobuf/compiler/rust/accessors/accessor_case.h"
@ -14,6 +15,7 @@
#include "google/protobuf/compiler/rust/accessors/generator.h"
#include "google/protobuf/compiler/rust/context.h"
#include "google/protobuf/compiler/rust/naming.h"
#include "google/protobuf/compiler/rust/upb_helpers.h"
#include "google/protobuf/descriptor.h"
namespace google {
@ -21,9 +23,43 @@ namespace protobuf {
namespace compiler {
namespace rust {
namespace {
// The upb function to use for the get/set functions, eg `Int32` for the
// functions `upb_Message_GetInt32` and upb_Message_SetInt32`.
std::string UpbCTypeNameForFunctions(const FieldDescriptor& field) {
switch (field.cpp_type()) {
case FieldDescriptor::CPPTYPE_INT32:
return "Int32";
case FieldDescriptor::CPPTYPE_INT64:
return "Int64";
case FieldDescriptor::CPPTYPE_UINT32:
return "UInt32";
case FieldDescriptor::CPPTYPE_UINT64:
return "UInt64";
case FieldDescriptor::CPPTYPE_DOUBLE:
return "Double";
case FieldDescriptor::CPPTYPE_FLOAT:
return "Float";
case FieldDescriptor::CPPTYPE_BOOL:
return "Bool";
case FieldDescriptor::CPPTYPE_ENUM:
return "Int32";
case FieldDescriptor::CPPTYPE_STRING:
case FieldDescriptor::CPPTYPE_MESSAGE:
// Handled by a different file.
break;
}
ABSL_CHECK(false) << "Unexpected field type: " << field.cpp_type_name();
return "";
}
} // namespace
void SingularScalar::InMsgImpl(Context& ctx, const FieldDescriptor& field,
AccessorCase accessor_case) const {
std::string field_name = FieldNameWithCollisionAvoidance(field);
ctx.Emit(
{
{"field", RsSafeName(field_name)},
@ -32,13 +68,37 @@ void SingularScalar::InMsgImpl(Context& ctx, const FieldDescriptor& field,
{"Scalar", RsTypePath(ctx, field)},
{"hazzer_thunk", ThunkName(ctx, field, "has")},
{"default_value", DefaultValue(ctx, field)},
{"upb_mt_field_index", UpbMiniTableFieldIndex(field)},
{"upb_fn_type_name", UpbCTypeNameForFunctions(field)},
{"getter",
[&] {
ctx.Emit(R"rs(
pub fn $field$($view_self$) -> $Scalar$ {
unsafe { $getter_thunk$(self.raw_msg()) }
}
)rs");
if (ctx.is_cpp()) {
ctx.Emit(R"rs(
pub fn $field$($view_self$) -> $Scalar$ {
unsafe { $getter_thunk$(self.raw_msg()) }
}
)rs");
} else {
ctx.Emit(
R"rs(
pub fn $field$($view_self$) -> $Scalar$ {
unsafe {
let mt = <Self as $pbr$::AssociatedMiniTable>::mini_table();
let f = $pbr$::upb_MiniTable_GetFieldByIndex(
mt, $upb_mt_field_index$);
// TODO: b/361751487: This .into() and .try_into() is only
// here for the enum<->i32 case, we should avoid it for
// other primitives where the types naturally match
// perfectly (and do an unchecked conversion for
// i32->enum types, since even for closed enums we trust
// upb to only return one of the named values).
$pbr$::upb_Message_Get$upb_fn_type_name$(
self.raw_msg(), f, ($default_value$).into()).try_into().unwrap()
}
}
)rs");
}
}},
{"getter_opt",
[&] {
@ -56,28 +116,70 @@ void SingularScalar::InMsgImpl(Context& ctx, const FieldDescriptor& field,
{"setter",
[&] {
if (accessor_case == AccessorCase::VIEW) return;
ctx.Emit({}, R"rs(
pub fn set_$raw_field_name$(&mut self, val: $Scalar$) {
unsafe { $setter_thunk$(self.raw_msg(), val) }
}
)rs");
if (ctx.is_cpp()) {
ctx.Emit(R"rs(
pub fn set_$raw_field_name$(&mut self, val: $Scalar$) {
unsafe { $setter_thunk$(self.raw_msg(), val) }
}
)rs");
} else {
ctx.Emit(R"rs(
pub fn set_$raw_field_name$(&mut self, val: $Scalar$) {
unsafe {
let mt = <Self as $pbr$::AssociatedMiniTable>::mini_table();
let f = $pbr$::upb_MiniTable_GetFieldByIndex(
mt, $upb_mt_field_index$);
// TODO: b/361751487: This .into() is only here
// here for the enum<->i32 case, we should avoid it for
// other primitives where the types naturally match
// perfectly.
$pbr$::upb_Message_SetBaseField$upb_fn_type_name$(
self.raw_msg(), f, val.into());
}
}
)rs");
}
}},
{"hazzer",
[&] {
if (!field.has_presence()) return;
ctx.Emit({}, R"rs(
pub fn has_$raw_field_name$($view_self$) -> bool {
unsafe { $hazzer_thunk$(self.raw_msg()) }
})rs");
if (ctx.is_cpp()) {
ctx.Emit(R"rs(
pub fn has_$raw_field_name$($view_self$) -> bool {
unsafe { $hazzer_thunk$(self.raw_msg()) }
})rs");
} else {
ctx.Emit(R"rs(
pub fn has_$raw_field_name$($view_self$) -> bool {
unsafe {
let mt = <Self as $pbr$::AssociatedMiniTable>::mini_table();
let f = $pbr$::upb_MiniTable_GetFieldByIndex(
mt, $upb_mt_field_index$);
$pbr$::upb_Message_HasBaseField(self.raw_msg(), f)
}
})rs");
}
}},
{"clearer",
[&] {
if (accessor_case == AccessorCase::VIEW) return;
if (!field.has_presence()) return;
ctx.Emit({}, R"rs(
pub fn clear_$raw_field_name$(&mut self) {
unsafe { $clearer_thunk$(self.raw_msg()) }
})rs");
if (ctx.is_cpp()) {
ctx.Emit(R"rs(
pub fn clear_$raw_field_name$(&mut self) {
unsafe { $clearer_thunk$(self.raw_msg()) }
})rs");
} else {
ctx.Emit(R"rs(
pub fn clear_$raw_field_name$(&mut self) {
unsafe {
let mt = <Self as $pbr$::AssociatedMiniTable>::mini_table();
let f = $pbr$::upb_MiniTable_GetFieldByIndex(
mt, $upb_mt_field_index$);
$pbr$::upb_Message_ClearBaseField(self.raw_msg(), f);
}
})rs");
}
}},
{"getter_thunk", ThunkName(ctx, field, "get")},
{"setter_thunk", ThunkName(ctx, field, "set")},
@ -94,6 +196,9 @@ void SingularScalar::InMsgImpl(Context& ctx, const FieldDescriptor& field,
void SingularScalar::InExternC(Context& ctx,
const FieldDescriptor& field) const {
// Only cpp kernel uses thunks.
if (ctx.is_upb()) return;
// In order to soundly pass a Rust type to C/C++ as a function argument,
// the types must be FFI-compatible.
// This requires special consideration for enums, which aren't trivial

@ -21,8 +21,8 @@
#include "google/protobuf/compiler/rust/enum.h"
#include "google/protobuf/compiler/rust/naming.h"
#include "google/protobuf/compiler/rust/oneof.h"
#include "google/protobuf/compiler/rust/upb_helpers.h"
#include "google/protobuf/descriptor.h"
#include "upb_generator/mangle.h"
namespace google {
namespace protobuf {
@ -30,10 +30,6 @@ namespace compiler {
namespace rust {
namespace {
std::string UpbMinitableName(const Descriptor& msg) {
return upb::generator::MessageInit(msg.full_name());
}
void MessageNew(Context& ctx, const Descriptor& msg) {
switch (ctx.opts().kernel) {
case Kernel::kCpp:
@ -75,7 +71,7 @@ void MessageSerialize(Context& ctx, const Descriptor& msg) {
return;
case Kernel::kUpb:
ctx.Emit({{"minitable", UpbMinitableName(msg)}},
ctx.Emit({{"minitable", UpbMiniTableName(msg)}},
R"rs(
// SAFETY: `MINI_TABLE` is the one associated with `self.raw_msg()`.
let encoded = unsafe {
@ -132,8 +128,8 @@ void MessageClearAndParse(Context& ctx, const Descriptor& msg) {
return;
case Kernel::kUpb:
ctx.Emit({{"minitable", UpbMinitableName(msg)}},
R"rs(
ctx.Emit(
R"rs(
let mut msg = Self::new();
// SAFETY:
@ -227,7 +223,7 @@ void MessageExterns(Context& ctx, const Descriptor& msg) {
ctx.Emit(
{
{"new_thunk", ThunkName(ctx, msg, "new")},
{"minitable", UpbMinitableName(msg)},
{"minitable", UpbMiniTableName(msg)},
},
R"rs(
fn $new_thunk$(arena: $pbr$::RawArena) -> $pbr$::RawMessage;
@ -274,7 +270,7 @@ void IntoProxiedForMessage(Context& ctx, const Descriptor& msg) {
return;
case Kernel::kUpb:
ctx.Emit({{"minitable", UpbMinitableName(msg)}}, R"rs(
ctx.Emit(R"rs(
impl<'msg> $pb$::IntoProxied<$Msg$> for $Msg$View<'msg> {
fn into_proxied(self, _private: $pbi$::Private) -> $Msg$ {
let dst = $Msg$::new();
@ -302,7 +298,7 @@ void IntoProxiedForMessage(Context& ctx, const Descriptor& msg) {
void UpbGeneratedMessageTraitImpls(Context& ctx, const Descriptor& msg) {
if (ctx.opts().kernel == Kernel::kUpb) {
ctx.Emit({{"minitable", UpbMinitableName(msg)}}, R"rs(
ctx.Emit({{"minitable", UpbMiniTableName(msg)}}, R"rs(
impl $pbr$::AssociatedMiniTable for $Msg$ {
#[inline(always)]
unsafe fn mini_table() -> *const $pbr$::upb_MiniTable {

@ -0,0 +1,40 @@
#include "google/protobuf/compiler/rust/upb_helpers.h"
#include <cstdint>
#include <string>
#include "absl/log/absl_check.h"
#include "google/protobuf/descriptor.h"
#include "upb_generator/mangle.h"
namespace google {
namespace protobuf {
namespace compiler {
namespace rust {
std::string UpbMiniTableName(const Descriptor& msg) {
return upb::generator::MessageInit(msg.full_name());
}
uint32_t UpbMiniTableFieldIndex(const FieldDescriptor& field) {
auto* parent = field.containing_type();
ABSL_CHECK(parent != nullptr);
// TODO: b/361751487 - We should get the field_index from
// UpbDefs directly, instead of independently matching
// the sort order here.
uint32_t num_fields_with_lower_field_number = 0;
for (int i = 0; i < parent->field_count(); ++i) {
if (parent->field(i)->number() < field.number()) {
++num_fields_with_lower_field_number;
}
}
return num_fields_with_lower_field_number;
}
} // namespace rust
} // namespace compiler
} // namespace protobuf
} // namespace google

@ -0,0 +1,32 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2024 Google LLC. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
#ifndef GOOGLE_PROTOBUF_COMPILER_RUST_UPB_HELPERS_H__
#define GOOGLE_PROTOBUF_COMPILER_RUST_UPB_HELPERS_H__
#include <cstdint>
#include <string>
#include "google/protobuf/descriptor.h"
namespace google {
namespace protobuf {
namespace compiler {
namespace rust {
// The symbol name for the MiniTable generated by upb MiniTable C codegen.
std::string UpbMiniTableName(const Descriptor& msg);
// The field index that the provided field will be in a upb_MiniTable.
uint32_t UpbMiniTableFieldIndex(const FieldDescriptor& field);
} // namespace rust
} // namespace compiler
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_COMPILER_RUST_UPB_HELPERS_H__
Loading…
Cancel
Save