Use a std::string as the backing string & bytes type in the C++ kernel. This will allow us to move a ProtoString/Bytes to a message accessor without copying. This change only touches the C++ kernel, as the UPB kernel already uses the native arena-allocated UPB string type for ProtoString/Bytes.

PiperOrigin-RevId: 649004435
pull/17306/head
Jakob Buchgraber 9 months ago committed by Copybara-Service
parent 0aa7449752
commit 64912c50cb
  1. 43
      rust/cpp.rs
  2. 12
      rust/cpp_kernel/strings.cc
  3. 12
      rust/cpp_kernel/strings.h

@ -64,6 +64,17 @@ mod _opaque_pointees {
_data: [u8; 0],
_marker: std::marker::PhantomData<(*mut u8, ::std::marker::PhantomPinned)>,
}
/// Opaque pointee for [`CppStdString`]
///
/// This type is not meant to be dereferenced in Rust code.
/// It is only meant to provide type safety for raw pointers
/// which are manipulated behind FFI.
#[repr(C)]
pub(super) struct CppStdStringData {
_data: [u8; 0],
_marker: std::marker::PhantomData<(*mut u8, ::std::marker::PhantomPinned)>,
}
}
/// A raw pointer to the underlying message for this runtime.
@ -75,25 +86,45 @@ pub type RawRepeatedField = NonNull<_opaque_pointees::RawRepeatedFieldData>;
/// A raw pointer to the underlying arena for this runtime.
pub type RawMap = NonNull<_opaque_pointees::RawMapData>;
/// A raw pointer to a std::string.
type CppStdString = NonNull<_opaque_pointees::CppStdStringData>;
/// Kernel-specific owned `string` and `bytes` field type.
// TODO - b/334788521: Allocate this on the C++ side (maybe as a std::string), and move the
// std::string instead of copying the string_view (which we currently do).
#[derive(Debug)]
pub struct InnerProtoString(Box<[u8]>);
pub struct InnerProtoString {
owned_ptr: CppStdString,
}
impl Drop for InnerProtoString {
fn drop(&mut self) {
// SAFETY: `self.owned_ptr` points to a valid std::string object.
unsafe {
proto2_rust_cpp_delete_string(self.owned_ptr);
}
}
}
impl InnerProtoString {
pub(crate) fn as_bytes(&self) -> &[u8] {
self.0.as_ref()
// SAFETY: `self.owned_ptr` points to a valid std::string object.
unsafe { proto2_rust_cpp_string_to_view(self.owned_ptr).as_ref() }
}
}
impl From<&[u8]> for InnerProtoString {
fn from(val: &[u8]) -> Self {
let owned_copy: Box<[u8]> = val.into();
InnerProtoString(owned_copy)
// SAFETY: `val` is valid byte slice.
let owned_ptr: CppStdString = unsafe { proto2_rust_cpp_new_string(val.into()) };
InnerProtoString { owned_ptr }
}
}
extern "C" {
fn proto2_rust_cpp_new_string(src: PtrAndLen) -> CppStdString;
fn proto2_rust_cpp_delete_string(src: CppStdString);
fn proto2_rust_cpp_string_to_view(src: CppStdString) -> PtrAndLen;
}
/// Represents an ABI-stable version of `NonNull<[u8]>`/`string_view` (a
/// borrowed slice of bytes) for FFI use only.
///

@ -24,3 +24,15 @@ RustStringRawParts::RustStringRawParts(std::string src) {
} // namespace rust
} // namespace protobuf
} // namespace google
extern "C" {
std::string* proto2_rust_cpp_new_string(google::protobuf::rust::PtrAndLen src) {
return new std::string(src.ptr, src.len);
}
void proto2_rust_cpp_delete_string(std::string* str) { delete str; }
google::protobuf::rust::PtrAndLen proto2_rust_cpp_string_to_view(std::string* str) {
return google::protobuf::rust::PtrAndLen(str->data(), str->length());
}
}

@ -47,4 +47,16 @@ struct RustStringRawParts {
} // namespace protobuf
} // namespace google
extern "C" {
// Allocates a new std::string on the C++ heap and returns a pointer to it.
std::string* proto2_rust_cpp_new_string(google::protobuf::rust::PtrAndLen src);
// Deletes a std::string object from the C++ heap.
void proto2_rust_cpp_delete_string(std::string* str);
// Obtain a PtrAndLen, the FFI-safe view type, from a std::string.
google::protobuf::rust::PtrAndLen proto2_rust_cpp_string_to_view(std::string* str);
}
#endif // GOOGLE_PROTOBUF_RUST_CPP_KERNEL_STRINGS_H__

Loading…
Cancel
Save