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__