From 2a6539eb57f9896ba14d0c604a553f01006be5b6 Mon Sep 17 00:00:00 2001 From: Protobuf Team Bot Date: Mon, 20 Oct 2025 07:19:35 -0700 Subject: [PATCH] Expose unstable message descriptor getter to Rust. PiperOrigin-RevId: 821637481 --- rust/codegen_traits.rs | 9 +++++++++ rust/cpp.rs | 1 + rust/cpp_kernel/message.cc | 17 +++++++++++++++++ rust/shared.rs | 2 ++ rust/test/cpp/interop/BUILD | 1 + rust/test/cpp/interop/main.rs | 13 ++++++++++++- rust/test/cpp/interop/test_utils.cc | 5 +++++ src/google/protobuf/compiler/rust/message.cc | 14 ++++++++++++++ 8 files changed, 61 insertions(+), 1 deletion(-) diff --git a/rust/codegen_traits.rs b/rust/codegen_traits.rs index 68dba5927d711..590689fc7bc4c 100644 --- a/rust/codegen_traits.rs +++ b/rust/codegen_traits.rs @@ -273,4 +273,13 @@ pub(crate) mod interop { #[cfg(cpp_kernel)] unsafe fn __unstable_wrap_raw_message_mut_unchecked_lifetime(raw: *mut c_void) -> Self; } + + /// A trait that provides a descriptor for a message. + /// This is only implemented by the messages that implement the + /// `proto2::Message` interface. + #[cfg(all(cpp_kernel, not(lite_runtime)))] + pub trait MessageDescriptorInterop { + /// Returns a pointer to a `proto2::Descriptor`. + fn __unstable_get_descriptor() -> *const std::ffi::c_void; + } } diff --git a/rust/cpp.rs b/rust/cpp.rs index cd64124fcaae3..653ba898a181b 100644 --- a/rust/cpp.rs +++ b/rust/cpp.rs @@ -112,6 +112,7 @@ unsafe extern "C" { pub fn proto2_rust_Message_serialize(m: RawMessage, output: &mut SerializedData) -> bool; pub fn proto2_rust_Message_copy_from(dst: RawMessage, src: RawMessage) -> bool; pub fn proto2_rust_Message_merge_from(dst: RawMessage, src: RawMessage) -> bool; + pub fn proto2_rust_Message_get_descriptor(m: RawMessage) -> *const std::ffi::c_void; } impl Drop for InnerProtoString { diff --git a/rust/cpp_kernel/message.cc b/rust/cpp_kernel/message.cc index 796f3c70dc092..402c64e076a28 100644 --- a/rust/cpp_kernel/message.cc +++ b/rust/cpp_kernel/message.cc @@ -1,9 +1,13 @@ +#include "google/protobuf/message.h" + #include #include "google/protobuf/message_lite.h" #include "rust/cpp_kernel/serialized_data.h" #include "rust/cpp_kernel/strings.h" +constexpr bool kHasFullRuntime = true; + extern "C" { void proto2_rust_Message_delete(google::protobuf::MessageLite* m) { delete m; } @@ -42,4 +46,17 @@ void proto2_rust_Message_merge_from(google::protobuf::MessageLite* dst, dst->CheckTypeAndMergeFrom(src); } +// Returns a pointer to the descriptor of the message, or nullptr if +// the message is not google::protobuf::Message. +const void* proto2_rust_Message_get_descriptor(const google::protobuf::MessageLite* m) { + if constexpr (kHasFullRuntime) { + auto msg = google::protobuf::DynamicCastMessage(m); + if (msg == nullptr) { + return nullptr; + } + return msg->GetDescriptor(); + } + return nullptr; +} + } // extern "C" diff --git a/rust/shared.rs b/rust/shared.rs index ae79f0c831916..01c22ade3b21e 100644 --- a/rust/shared.rs +++ b/rust/shared.rs @@ -14,6 +14,8 @@ use std::fmt; // This problem is referred to as "perfect derive". // https://smallcultfollowing.com/babysteps/blog/2022/04/12/implied-bounds-and-perfect-derive/ +#[cfg(all(cpp_kernel, not(lite_runtime)))] +pub use crate::codegen_traits::interop::MessageDescriptorInterop; pub use crate::codegen_traits::{ create::Parse, interop::{MessageMutInterop, MessageViewInterop, OwnedMessageInterop}, diff --git a/rust/test/cpp/interop/BUILD b/rust/test/cpp/interop/BUILD index 8854d66696e75..e01995aba5ab7 100644 --- a/rust/test/cpp/interop/BUILD +++ b/rust/test/cpp/interop/BUILD @@ -15,6 +15,7 @@ cc_library( deps = [ ":interop_test_cc_proto", "//rust/cpp_kernel:cpp_api", + "//src/google/protobuf", "@abseil-cpp//absl/log:absl_check", "@abseil-cpp//absl/strings", ], diff --git a/rust/test/cpp/interop/main.rs b/rust/test/cpp/interop/main.rs index 5bff0bd3ca3d2..88fc3d964f164 100644 --- a/rust/test/cpp/interop/main.rs +++ b/rust/test/cpp/interop/main.rs @@ -9,7 +9,9 @@ use googletest::prelude::*; use protobuf_cpp::prelude::*; use protobuf_cpp::__internal::runtime::PtrAndLen; -use protobuf_cpp::{MessageMutInterop, MessageViewInterop, OwnedMessageInterop}; +use protobuf_cpp::{ + MessageDescriptorInterop, MessageMutInterop, MessageViewInterop, OwnedMessageInterop, +}; use std::ffi::c_void; use interop_test_rust_proto::{InteropTestMessage, InteropTestMessageMut, InteropTestMessageView}; @@ -40,6 +42,8 @@ unsafe extern "C" { fn GetBytesExtension(msg: *const c_void) -> PtrAndLen; fn GetConstStaticInteropTestMessage() -> *const c_void; + + fn IsExpectedDescriptor(provided: *const c_void) -> bool; } #[gtest] @@ -155,3 +159,10 @@ fn view_of_const_static() { assert_eq!(view.i64(), 0); assert_eq!(view.default_int32(), 41); } + +#[gtest] +fn descriptor_interop() { + let descriptor = InteropTestMessage::__unstable_get_descriptor(); + let result = unsafe { IsExpectedDescriptor(descriptor) }; + assert!(result); +} diff --git a/rust/test/cpp/interop/test_utils.cc b/rust/test/cpp/interop/test_utils.cc index b95168562f4c5..6d5d7cd88f5c8 100644 --- a/rust/test/cpp/interop/test_utils.cc +++ b/rust/test/cpp/interop/test_utils.cc @@ -10,6 +10,7 @@ #include "absl/log/absl_check.h" #include "absl/strings/string_view.h" +#include "google/protobuf/descriptor.h" #include "rust/cpp_kernel/serialized_data.h" #include "rust/cpp_kernel/strings.h" #include "rust/test/cpp/interop/interop_test.pb.h" @@ -64,3 +65,7 @@ extern "C" const void* GetConstStaticInteropTestMessage() { static const auto* msg = new InteropTestMessage; return msg; } + +extern "C" bool IsExpectedDescriptor(const google::protobuf::Descriptor* descriptor) { + return descriptor == InteropTestMessage::GetDescriptor(); +} diff --git a/src/google/protobuf/compiler/rust/message.cc b/src/google/protobuf/compiler/rust/message.cc index 3a4e6bb01fdda..0566fe8c98587 100644 --- a/src/google/protobuf/compiler/rust/message.cc +++ b/src/google/protobuf/compiler/rust/message.cc @@ -857,6 +857,20 @@ void GenerateRs(Context& ctx, const Descriptor& msg, const upb::DefPool& pool) { } } )rs"); + + // TODO: Check if we are in a forced lite runtime in addition + // to the existing check. + if (msg.file()->options().optimize_for() != FileOptions::LITE_RUNTIME) { + ctx.Emit({{"Msg", RsSafeName(msg.name())}}, + R"rs( + #[cfg(all(cpp_kernel, not(lite_runtime)))] + impl $pb$::MessageDescriptorInterop for $Msg$ { + fn __unstable_get_descriptor() -> *const $std$::ffi::c_void { + unsafe { $pbr$::proto2_rust_Message_get_descriptor(<$Msg$View as Default>::default().raw_msg()) } + } + } + )rs"); + } } } // NOLINT(readability/fn_size)