diff --git a/rust/cpp_kernel/BUILD b/rust/cpp_kernel/BUILD index ef04dd41d4..7d0a256f1c 100644 --- a/rust/cpp_kernel/BUILD +++ b/rust/cpp_kernel/BUILD @@ -4,8 +4,19 @@ load("@rules_rust//rust:defs.bzl", "rust_library") cc_library( name = "cpp_api", - srcs = ["cpp_api.cc"], - hdrs = ["cpp_api.h"], + srcs = [ + "debug.cc", + "map.cc", + "repeated.cc", + "strings.cc", + ], + hdrs = [ + "debug.h", + "map.h", + "rust_alloc_for_cpp_api.h", + "serialized_data.h", + "strings.h", + ], visibility = [ "//rust:__subpackages__", "//src/google/protobuf:__subpackages__", diff --git a/rust/cpp_kernel/debug.cc b/rust/cpp_kernel/debug.cc new file mode 100644 index 0000000000..29f584620f --- /dev/null +++ b/rust/cpp_kernel/debug.cc @@ -0,0 +1,23 @@ +#include "rust/cpp_kernel/debug.h" + +#include + +#include "google/protobuf/message.h" +#include "google/protobuf/message_lite.h" +#include "rust/cpp_kernel/strings.h" + +extern "C" { + +google::protobuf::rust_internal::RustStringRawParts utf8_debug_string( + const google::protobuf::Message* msg) { + std::string text = google::protobuf::Utf8Format(*msg); + return google::protobuf::rust_internal::RustStringRawParts(text); +} + +google::protobuf::rust_internal::RustStringRawParts utf8_debug_string_lite( + const google::protobuf::MessageLite* msg) { + std::string text = google::protobuf::Utf8Format(*msg); + return google::protobuf::rust_internal::RustStringRawParts(text); +} + +} // extern "C" diff --git a/rust/cpp_kernel/debug.h b/rust/cpp_kernel/debug.h new file mode 100644 index 0000000000..6a6c1d89eb --- /dev/null +++ b/rust/cpp_kernel/debug.h @@ -0,0 +1,18 @@ +#ifndef GOOGLE_PROTOBUF_RUST_CPP_KERNEL_DEBUG_H__ +#define GOOGLE_PROTOBUF_RUST_CPP_KERNEL_DEBUG_H__ + +#include "google/protobuf/message.h" +#include "google/protobuf/message_lite.h" +#include "rust/cpp_kernel/strings.h" + +extern "C" { + +google::protobuf::rust_internal::RustStringRawParts utf8_debug_string( + const google::protobuf::Message* msg); + +google::protobuf::rust_internal::RustStringRawParts utf8_debug_string_lite( + const google::protobuf::MessageLite* msg); + +} // extern "C" + +#endif // GOOGLE_PROTOBUF_RUST_CPP_KERNEL_DEBUG_H__ diff --git a/rust/cpp_kernel/map.cc b/rust/cpp_kernel/map.cc new file mode 100644 index 0000000000..19d333cbc5 --- /dev/null +++ b/rust/cpp_kernel/map.cc @@ -0,0 +1,39 @@ +#include "rust/cpp_kernel/map.h" + +#include +#include + +#include "google/protobuf/map.h" +#include "rust/cpp_kernel/strings.h" + +extern "C" { + +void __rust_proto_thunk__UntypedMapIterator_increment( + google::protobuf::internal::UntypedMapIterator* iter) { + iter->PlusPlus(); +} + +__PB_RUST_EXPOSE_SCALAR_MAP_METHODS_FOR_VALUE_TYPE(int32_t, i32, int32_t, value, + cpp_value); +__PB_RUST_EXPOSE_SCALAR_MAP_METHODS_FOR_VALUE_TYPE(uint32_t, u32, uint32_t, + value, cpp_value); +__PB_RUST_EXPOSE_SCALAR_MAP_METHODS_FOR_VALUE_TYPE(float, f32, float, value, + cpp_value); +__PB_RUST_EXPOSE_SCALAR_MAP_METHODS_FOR_VALUE_TYPE(double, f64, double, value, + cpp_value); +__PB_RUST_EXPOSE_SCALAR_MAP_METHODS_FOR_VALUE_TYPE(bool, bool, bool, value, + cpp_value); +__PB_RUST_EXPOSE_SCALAR_MAP_METHODS_FOR_VALUE_TYPE(uint64_t, u64, uint64_t, + value, cpp_value); +__PB_RUST_EXPOSE_SCALAR_MAP_METHODS_FOR_VALUE_TYPE(int64_t, i64, int64_t, value, + cpp_value); +__PB_RUST_EXPOSE_SCALAR_MAP_METHODS_FOR_VALUE_TYPE( + std::string, ProtoBytes, google::protobuf::rust_internal::PtrAndLen, + std::string(value.ptr, value.len), + google::protobuf::rust_internal::PtrAndLen(cpp_value.data(), cpp_value.size())); +__PB_RUST_EXPOSE_SCALAR_MAP_METHODS_FOR_VALUE_TYPE( + std::string, ProtoString, google::protobuf::rust_internal::PtrAndLen, + std::string(value.ptr, value.len), + google::protobuf::rust_internal::PtrAndLen(cpp_value.data(), cpp_value.size())); + +} // extern "C" diff --git a/rust/cpp_kernel/cpp_api.h b/rust/cpp_kernel/map.h similarity index 68% rename from rust/cpp_kernel/cpp_api.h rename to rust/cpp_kernel/map.h index 24765f63a7..9f1038b579 100644 --- a/rust/cpp_kernel/cpp_api.h +++ b/rust/cpp_kernel/map.h @@ -1,79 +1,5 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2023 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 - -// This file contains support code for generated C++ thunks. - -#ifndef GOOGLE_PROTOBUF_RUST_CPP_KERNEL_CPP_H__ -#define GOOGLE_PROTOBUF_RUST_CPP_KERNEL_CPP_H__ - -#include -#include -#include -#include -#include - -#include "absl/log/absl_check.h" -#include "absl/log/absl_log.h" -#include "google/protobuf/message.h" -#include "google/protobuf/message_lite.h" - -namespace google { -namespace protobuf { -namespace rust_internal { - -// Represents serialized Protobuf wire format data. -// -// Only to be used to transfer serialized data from C++ to Rust under these -// assumptions: -// * Rust and C++ versions of this struct are ABI compatible. -// * Rust version owns and frees its data. -// * The data were allocated using the Rust allocator. -// -extern "C" struct SerializedData { - // Owns the memory, must be freed by Rust. - const uint8_t* data; - size_t len; - - SerializedData(const uint8_t* data, size_t len) : data(data), len(len) {} -}; - -// Allocates memory using the current Rust global allocator. -// -// This function is defined in `rust_alloc_for_cpp_api.rs`. -extern "C" void* __pb_rust_alloc(size_t size, size_t align); - -inline bool SerializeMsg(const google::protobuf::MessageLite* msg, SerializedData* out) { - ABSL_DCHECK(msg->IsInitialized()); - size_t len = msg->ByteSizeLong(); - if (len > INT_MAX) { - ABSL_LOG(ERROR) << msg->GetTypeName() - << " exceeded maximum protobuf size of 2GB: " << len; - return false; - } - uint8_t* bytes = static_cast(__pb_rust_alloc(len, alignof(char))); - if (bytes == nullptr) { - ABSL_LOG(FATAL) << "Rust allocator failed to allocate memory."; - } - if (!msg->SerializeWithCachedSizesToArray(bytes)) { - return false; - } - *out = SerializedData(bytes, len); - return true; -} - -// Represents an ABI-stable version of &[u8]/string_view (borrowed slice of -// bytes) for FFI use only. -struct PtrAndLen { - /// Borrows the memory. - const char* ptr; - size_t len; - - PtrAndLen(const char* ptr, size_t len) : ptr(ptr), len(len) {} -}; +#ifndef GOOGLE_PROTOBUF_RUST_CPP_KERNEL_MAP_H__ +#define GOOGLE_PROTOBUF_RUST_CPP_KERNEL_MAP_H__ // Defines concrete thunks to access typed map methods from Rust. #define __PB_RUST_EXPOSE_SCALAR_MAP_METHODS( \ @@ -161,28 +87,4 @@ struct PtrAndLen { google::protobuf::rust_internal::PtrAndLen(cpp_key.data(), cpp_key.size()), \ value_ty, rust_value_ty, ffi_value_ty, to_cpp_value, to_ffi_value); -// Represents an owned string for FFI purposes. -// -// This must only be used to transfer a string from C++ to Rust. The -// below invariants must hold: -// * Rust and C++ versions of this struct are ABI compatible. -// * The data were allocated using the Rust allocator and are 1 byte aligned. -// * The data is valid UTF-8. -struct RustStringRawParts { - // Owns the memory. - const char* data; - size_t len; - - RustStringRawParts() = delete; - // Copies src. - explicit RustStringRawParts(std::string src); -}; - -extern "C" RustStringRawParts utf8_debug_string(const google::protobuf::Message* msg); -extern "C" RustStringRawParts utf8_debug_string_lite( - const google::protobuf::MessageLite* msg); -} // namespace rust_internal -} // namespace protobuf -} // namespace google - -#endif // GOOGLE_PROTOBUF_RUST_CPP_KERNEL_CPP_H__ +#endif // GOOGLE_PROTOBUF_RUST_CPP_KERNEL_MAP_H__ diff --git a/rust/cpp_kernel/cpp_api.cc b/rust/cpp_kernel/repeated.cc similarity index 71% rename from rust/cpp_kernel/cpp_api.cc rename to rust/cpp_kernel/repeated.cc index d41a485075..63e8d5ade5 100644 --- a/rust/cpp_kernel/cpp_api.cc +++ b/rust/cpp_kernel/repeated.cc @@ -1,15 +1,13 @@ -#include "rust/cpp_kernel/cpp_api.h" - #include #include #include #include -#include "google/protobuf/map.h" #include "google/protobuf/message.h" #include "google/protobuf/message_lite.h" #include "google/protobuf/repeated_field.h" #include "google/protobuf/repeated_ptr_field.h" +#include "rust/cpp_kernel/strings.h" extern "C" { #define expose_repeated_field_methods(ty, rust_ty) \ @@ -106,66 +104,4 @@ expose_repeated_ptr_field_methods(ProtoBytes); #undef expose_repeated_ptr_field_methods -void __rust_proto_thunk__UntypedMapIterator_increment( - google::protobuf::internal::UntypedMapIterator* iter) { - iter->PlusPlus(); -} - -__PB_RUST_EXPOSE_SCALAR_MAP_METHODS_FOR_VALUE_TYPE(int32_t, i32, int32_t, value, - cpp_value); -__PB_RUST_EXPOSE_SCALAR_MAP_METHODS_FOR_VALUE_TYPE(uint32_t, u32, uint32_t, - value, cpp_value); -__PB_RUST_EXPOSE_SCALAR_MAP_METHODS_FOR_VALUE_TYPE(float, f32, float, value, - cpp_value); -__PB_RUST_EXPOSE_SCALAR_MAP_METHODS_FOR_VALUE_TYPE(double, f64, double, value, - cpp_value); -__PB_RUST_EXPOSE_SCALAR_MAP_METHODS_FOR_VALUE_TYPE(bool, bool, bool, value, - cpp_value); -__PB_RUST_EXPOSE_SCALAR_MAP_METHODS_FOR_VALUE_TYPE(uint64_t, u64, uint64_t, - value, cpp_value); -__PB_RUST_EXPOSE_SCALAR_MAP_METHODS_FOR_VALUE_TYPE(int64_t, i64, int64_t, value, - cpp_value); -__PB_RUST_EXPOSE_SCALAR_MAP_METHODS_FOR_VALUE_TYPE( - std::string, ProtoBytes, google::protobuf::rust_internal::PtrAndLen, - std::string(value.ptr, value.len), - google::protobuf::rust_internal::PtrAndLen(cpp_value.data(), cpp_value.size())); -__PB_RUST_EXPOSE_SCALAR_MAP_METHODS_FOR_VALUE_TYPE( - std::string, ProtoString, google::protobuf::rust_internal::PtrAndLen, - std::string(value.ptr, value.len), - google::protobuf::rust_internal::PtrAndLen(cpp_value.data(), cpp_value.size())); - -#undef expose_scalar_map_methods -#undef expose_map_methods - -google::protobuf::rust_internal::RustStringRawParts utf8_debug_string( - const google::protobuf::Message* msg) { - std::string text = google::protobuf::Utf8Format(*msg); - return google::protobuf::rust_internal::RustStringRawParts(text); -} - -google::protobuf::rust_internal::RustStringRawParts utf8_debug_string_lite( - const google::protobuf::MessageLite* msg) { - std::string text = google::protobuf::Utf8Format(*msg); - return google::protobuf::rust_internal::RustStringRawParts(text); -} -} - -namespace google { -namespace protobuf { -namespace rust_internal { - -RustStringRawParts::RustStringRawParts(std::string src) { - if (src.empty()) { - data = nullptr; - len = 0; - } else { - void* data_ = google::protobuf::rust_internal::__pb_rust_alloc(src.length(), 1); - std::memcpy(data_, src.data(), src.length()); - data = static_cast(data_); - len = src.length(); - } -} - -} // namespace rust_internal -} // namespace protobuf -} // namespace google +} // extern "C" diff --git a/rust/cpp_kernel/rust_alloc_for_cpp_api.h b/rust/cpp_kernel/rust_alloc_for_cpp_api.h new file mode 100644 index 0000000000..d69041b07a --- /dev/null +++ b/rust/cpp_kernel/rust_alloc_for_cpp_api.h @@ -0,0 +1,11 @@ +#ifndef GOOGLE_PROTOBUF_RUST_CPP_KERNEL_RUST_ALLOC_FOR_CPP_API_H__ +#define GOOGLE_PROTOBUF_RUST_CPP_KERNEL_RUST_ALLOC_FOR_CPP_API_H__ + +#include + +// Allocates memory using the current Rust global allocator. +// +// This function is defined in `rust_alloc_for_cpp_api.rs`. +extern "C" void* __pb_rust_alloc(size_t size, size_t align); + +#endif // GOOGLE_PROTOBUF_RUST_CPP_KERNEL_RUST_ALLOC_FOR_CPP_API_H__ diff --git a/rust/cpp_kernel/serialized_data.h b/rust/cpp_kernel/serialized_data.h new file mode 100644 index 0000000000..20401c80fb --- /dev/null +++ b/rust/cpp_kernel/serialized_data.h @@ -0,0 +1,64 @@ +// 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_RUST_CPP_KERNEL_SERIALIZED_DATA_H__ +#define GOOGLE_PROTOBUF_RUST_CPP_KERNEL_SERIALIZED_DATA_H__ + +#include +#include +#include +#include + +#include "absl/log/absl_check.h" +#include "absl/log/absl_log.h" +#include "google/protobuf/message_lite.h" +#include "rust/cpp_kernel/rust_alloc_for_cpp_api.h" + +namespace google { +namespace protobuf { +namespace rust_internal { + +// Represents serialized Protobuf wire format data. +// +// Only to be used to transfer serialized data from C++ to Rust under these +// assumptions: +// * Rust and C++ versions of this struct are ABI compatible. +// * Rust version owns and frees its data. +// * The data were allocated using the Rust allocator. +// +extern "C" struct SerializedData { + // Owns the memory, must be freed by Rust. + const uint8_t* data; + size_t len; + + SerializedData(const uint8_t* data, size_t len) : data(data), len(len) {} +}; + +inline bool SerializeMsg(const google::protobuf::MessageLite* msg, SerializedData* out) { + ABSL_DCHECK(msg->IsInitialized()); + size_t len = msg->ByteSizeLong(); + if (len > INT_MAX) { + ABSL_LOG(ERROR) << msg->GetTypeName() + << " exceeded maximum protobuf size of 2GB: " << len; + return false; + } + uint8_t* bytes = static_cast(__pb_rust_alloc(len, alignof(char))); + if (bytes == nullptr) { + ABSL_LOG(FATAL) << "Rust allocator failed to allocate memory."; + } + if (!msg->SerializeWithCachedSizesToArray(bytes)) { + return false; + } + *out = SerializedData(bytes, len); + return true; +} + +} // namespace rust_internal +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_RUST_CPP_KERNEL_SERIALIZED_DATA_H__ diff --git a/rust/cpp_kernel/strings.cc b/rust/cpp_kernel/strings.cc new file mode 100644 index 0000000000..5b069e2d48 --- /dev/null +++ b/rust/cpp_kernel/strings.cc @@ -0,0 +1,26 @@ +#include "rust/cpp_kernel/strings.h" + +#include +#include + +#include "rust/cpp_kernel/rust_alloc_for_cpp_api.h" + +namespace google { +namespace protobuf { +namespace rust_internal { + +RustStringRawParts::RustStringRawParts(std::string src) { + if (src.empty()) { + data = nullptr; + len = 0; + } else { + void* d = __pb_rust_alloc(src.length(), 1); + std::memcpy(d, src.data(), src.length()); + data = static_cast(d); + len = src.length(); + } +} + +} // namespace rust_internal +} // namespace protobuf +} // namespace google diff --git a/rust/cpp_kernel/strings.h b/rust/cpp_kernel/strings.h new file mode 100644 index 0000000000..400a04afb3 --- /dev/null +++ b/rust/cpp_kernel/strings.h @@ -0,0 +1,50 @@ +// 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_RUST_CPP_KERNEL_STRINGS_H__ +#define GOOGLE_PROTOBUF_RUST_CPP_KERNEL_STRINGS_H__ + +#include +#include +#include + +namespace google { +namespace protobuf { +namespace rust_internal { + +// Represents an ABI-stable version of &[u8]/string_view (borrowed slice of +// bytes) for FFI use only. +struct PtrAndLen { + /// Borrows the memory. + const char* ptr; + size_t len; + + PtrAndLen(const char* ptr, size_t len) : ptr(ptr), len(len) {} +}; + +// Represents an owned string for FFI purposes. +// +// This must only be used to transfer a string from C++ to Rust. The +// below invariants must hold: +// * Rust and C++ versions of this struct are ABI compatible. +// * The data were allocated using the Rust allocator and are 1 byte aligned. +// * The data is valid UTF-8. +struct RustStringRawParts { + // Owns the memory. + const char* data; + size_t len; + + RustStringRawParts() = delete; + // Copies src. + explicit RustStringRawParts(std::string src); +}; + +} // namespace rust_internal +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_RUST_CPP_KERNEL_STRINGS_H__ diff --git a/rust/test/cpp/interop/test_utils.cc b/rust/test/cpp/interop/test_utils.cc index a3010df7f8..33e51239a9 100644 --- a/rust/test/cpp/interop/test_utils.cc +++ b/rust/test/cpp/interop/test_utils.cc @@ -10,7 +10,8 @@ #include "absl/log/absl_check.h" #include "absl/strings/string_view.h" -#include "rust/cpp_kernel/cpp_api.h" +#include "rust/cpp_kernel/serialized_data.h" +#include "rust/cpp_kernel/strings.h" #include "google/protobuf/unittest.pb.h" using google::protobuf::rust_internal::SerializedData; diff --git a/src/google/protobuf/compiler/rust/generator.cc b/src/google/protobuf/compiler/rust/generator.cc index 49f1e65897..390c7ba447 100644 --- a/src/google/protobuf/compiler/rust/generator.cc +++ b/src/google/protobuf/compiler/rust/generator.cc @@ -217,7 +217,9 @@ bool RustGenerator::Generate(const FileDescriptor* file, R"cc( #include "$proto_h$" $proto_deps_h$ -#include "google/protobuf/rust/cpp_kernel/cpp_api.h" +#include "google/protobuf/rust/cpp_kernel/map.h" +#include "google/protobuf/rust/cpp_kernel/serialized_data.h" +#include "google/protobuf/rust/cpp_kernel/strings.h" )cc"); }