Change upb singular scalar accessors to not use upb C accessor codegen.
PiperOrigin-RevId: 666879420
diff --git a/rust/upb/lib.rs b/rust/upb/lib.rs
index 125a0f2..a24f78e 100644
--- a/rust/upb/lib.rs
+++ b/rust/upb/lib.rs
@@ -34,19 +34,15 @@
};
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;
diff --git a/rust/upb/message.rs b/rust/upb/message.rs
index b78e495..caaa80a 100644
--- a/rust/upb/message.rs
+++ b/rust/upb/message.rs
@@ -13,17 +13,22 @@
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 @@
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 @@
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 @@
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 @@
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);
}
diff --git a/rust/upb/mini_table.rs b/rust/upb/mini_table.rs
index 64b64ec..cfc19c8 100644
--- a/rust/upb/mini_table.rs
+++ b/rust/upb/mini_table.rs
@@ -19,4 +19,9 @@
m: *const upb_MiniTable,
number: u32,
) -> *const upb_MiniTableField;
+
+ pub fn upb_MiniTable_GetFieldByIndex(
+ m: *const upb_MiniTable,
+ number: u32,
+ ) -> *const upb_MiniTableField;
}
diff --git a/src/google/protobuf/compiler/rust/BUILD.bazel b/src/google/protobuf/compiler/rust/BUILD.bazel
index 5ff8f51..fd28df6 100644
--- a/src/google/protobuf/compiler/rust/BUILD.bazel
+++ b/src/google/protobuf/compiler/rust/BUILD.bazel
@@ -86,11 +86,11 @@
":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 @@
"@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",
+ ],
+)
diff --git a/src/google/protobuf/compiler/rust/accessors/BUILD.bazel b/src/google/protobuf/compiler/rust/accessors/BUILD.bazel
index 15bc15f..f5ff57e 100644
--- a/src/google/protobuf/compiler/rust/accessors/BUILD.bazel
+++ b/src/google/protobuf/compiler/rust/accessors/BUILD.bazel
@@ -37,6 +37,7 @@
"//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",
diff --git a/src/google/protobuf/compiler/rust/accessors/default_value.cc b/src/google/protobuf/compiler/rust/accessors/default_value.cc
index 27594b3..c31bf75 100644
--- a/src/google/protobuf/compiler/rust/accessors/default_value.cc
+++ b/src/google/protobuf/compiler/rust/accessors/default_value.cc
@@ -58,13 +58,13 @@
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:
diff --git a/src/google/protobuf/compiler/rust/accessors/repeated_field.cc b/src/google/protobuf/compiler/rust/accessors/repeated_field.cc
index 797ac8f..04e638e 100644
--- a/src/google/protobuf/compiler/rust/accessors/repeated_field.cc
+++ b/src/google/protobuf/compiler/rust/accessors/repeated_field.cc
@@ -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 @@
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);
diff --git a/src/google/protobuf/compiler/rust/accessors/singular_scalar.cc b/src/google/protobuf/compiler/rust/accessors/singular_scalar.cc
index a3d5c62..904f36d 100644
--- a/src/google/protobuf/compiler/rust/accessors/singular_scalar.cc
+++ b/src/google/protobuf/compiler/rust/accessors/singular_scalar.cc
@@ -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 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 @@
{"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 @@
{"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::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
diff --git a/src/google/protobuf/compiler/rust/message.cc b/src/google/protobuf/compiler/rust/message.cc
index be85bff..a7d119b 100644
--- a/src/google/protobuf/compiler/rust/message.cc
+++ b/src/google/protobuf/compiler/rust/message.cc
@@ -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 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 @@
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 @@
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 @@
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 @@
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 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 {
diff --git a/src/google/protobuf/compiler/rust/upb_helpers.cc b/src/google/protobuf/compiler/rust/upb_helpers.cc
new file mode 100644
index 0000000..c573599
--- /dev/null
+++ b/src/google/protobuf/compiler/rust/upb_helpers.cc
@@ -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
diff --git a/src/google/protobuf/compiler/rust/upb_helpers.h b/src/google/protobuf/compiler/rust/upb_helpers.h
new file mode 100644
index 0000000..312afbf
--- /dev/null
+++ b/src/google/protobuf/compiler/rust/upb_helpers.h
@@ -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__