Generate C++ thunks for Rust protos
In this CL I'd like to call existing C++ Protobuf API from the V0 Rust API. Since parts of the C++ API are defined inline and using (obviously) C++ name mangling, we need to create a "thunks.cc" file that:
1) Generates code for C++ API function we use from Rust
2) Exposes these functions without any name mangling (meaning using `extern "C"`)
In this CL we add Bazel logic to generate "thunks" file, compile it, and propagate its object to linking. We also add logic to protoc to generate this "thunks" file.
The protoc logic is rather rudimentary still. I hope to focus on protoc code quality in my followup work on V0 Rust API using C++ kernel.
PiperOrigin-RevId: 523479839
diff --git a/rust/upb_kernel/upb.rs b/rust/upb_kernel/upb.rs
index 41a8359..9f4bb90 100644
--- a/rust/upb_kernel/upb.rs
+++ b/rust/upb_kernel/upb.rs
@@ -31,6 +31,10 @@
// Rust Protobuf runtime using the UPB kernel.
/// Represents UPB's upb_Arena.
+use std::ops::Deref;
+use std::ptr::NonNull;
+use std::slice;
+
#[repr(C)]
pub struct Arena {
_data: [u8; 0],
@@ -52,6 +56,34 @@
pub fn upb_Arena_Free(arena: *mut Arena);
}
+/// Represents serialized Protobuf wire format data. It's typically produced by
+/// `<Message>.serialize()`.
+#[derive(Debug)]
+pub struct SerializedData {
+ data: NonNull<u8>,
+ len: usize,
+ arena: *mut Arena,
+}
+
+impl SerializedData {
+ pub unsafe fn from_raw_parts(arena: *mut Arena, data: NonNull<u8>, len: usize) -> Self {
+ SerializedData { arena, data, len }
+ }
+}
+
+impl Deref for SerializedData {
+ type Target = [u8];
+ fn deref(&self) -> &Self::Target {
+ unsafe { slice::from_raw_parts(self.data.as_ptr() as *const _, self.len) }
+ }
+}
+
+impl Drop for SerializedData {
+ fn drop(&mut self) {
+ unsafe { Arena::free(self.arena) };
+ }
+}
+
#[cfg(test)]
mod tests {
use super::*;
@@ -61,4 +93,20 @@
let arena = unsafe { Arena::new() };
unsafe { Arena::free(arena) };
}
+
+ #[test]
+ fn test_serialized_data_roundtrip() {
+ let arena = unsafe { Arena::new() };
+ let original_data = b"Hello world";
+ let len = original_data.len();
+
+ let serialized_data = unsafe {
+ SerializedData::from_raw_parts(
+ arena,
+ NonNull::new(original_data as *const _ as *mut _).unwrap(),
+ len,
+ )
+ };
+ assert_eq!(&*serialized_data, b"Hello world");
+ }
}