Configure the build for the Rust UPB backend
In this CL we're adding the barebones infrastructure to generate Rust proto messages using UPB as a backend. The API is what we call a V0, not yet production-quality, not yet rigorously designed, just something to enable parallel work.
The interesting part of switching backend between UPB and C++ will come in a followup.
PiperOrigin-RevId: 517089760
diff --git a/rust/BUILD b/rust/BUILD
index ac72f07..30dbd1e 100644
--- a/rust/BUILD
+++ b/rust/BUILD
@@ -1,6 +1,6 @@
# Protobuf Rust runtime packages.
-load("@rules_rust//rust:defs.bzl", "rust_library")
+load("@rules_rust//rust:defs.bzl", "rust_library", "rust_test")
load("@rules_proto//proto:defs.bzl", "proto_lang_toolchain")
package(default_visibility = ["//src/google/protobuf:__subpackages__"])
@@ -8,6 +8,16 @@
rust_library(
name = "protobuf",
srcs = ["lib.rs"],
+ deps = ["//rust/upb_backend:upb"],
+)
+
+rust_test(
+ name = "protobuf_test",
+ crate = ":protobuf",
+ tags = [
+ "not_build:arm",
+ "notsan",
+ ],
)
# TODO(b/270125787): Move to the right location once rust_proto_library is no longer experimental.
diff --git a/rust/defs.bzl b/rust/defs.bzl
index 8e7d47e..af42f51 100644
--- a/rust/defs.bzl
+++ b/rust/defs.bzl
@@ -9,6 +9,7 @@
# buildifier: disable=bzl-visibility
load("@rules_rust//rust/private:rustc.bzl", "rustc_compile_action")
load("@rules_rust//rust:defs.bzl", "rust_common")
+load("//third_party/upb/bazel:upb_proto_library.bzl", "UpbWrappedCcInfo", "upb_proto_library_aspect")
proto_common = proto_common_do_not_use
@@ -155,13 +156,18 @@
build_info = None,
)
+ upb_gencode_cc_info = target[UpbWrappedCcInfo].cc_info_with_thunks
+ upb_gencode_dep_variant_info = DepVariantInfo(cc_info = upb_gencode_cc_info)
+
proto_dep = getattr(ctx.rule.attr, "deps", [])
dep_variant_info = _compile_rust(
ctx = ctx,
attr = ctx.rule.attr,
src = gencode[0],
extra_srcs = gencode[1:],
- deps = [dep_variant_info_for_runtime] + ([proto_dep[0][RustProtoInfo].dep_variant_info] if proto_dep else []),
+ deps = [dep_variant_info_for_runtime, upb_gencode_dep_variant_info] + (
+ [proto_dep[0][RustProtoInfo].dep_variant_info] if proto_dep else []
+ ),
)
return [RustProtoInfo(
dep_variant_info = dep_variant_info,
@@ -170,6 +176,7 @@
rust_proto_library_aspect = aspect(
implementation = _rust_proto_aspect_impl,
attr_aspects = ["deps"],
+ requires = [upb_proto_library_aspect],
attrs = {
"_cc_toolchain": attr.label(
doc = (
diff --git a/rust/lib.rs b/rust/lib.rs
index d860245..0aaeb2d 100644
--- a/rust/lib.rs
+++ b/rust/lib.rs
@@ -30,7 +30,56 @@
//! Rust Protobuf Runtime
-// Not yet implemented.
+pub use upb::*;
-// TODO(b/270138878): Remove once we have real logic in the runtime.
-pub fn do_nothing() {}
+use std::ops::Deref;
+use std::ptr::NonNull;
+use std::slice;
+
+/// Represents serialized Protobuf wire format data. It's typically produced by
+/// `<Message>.serialize()`.
+pub struct SerializedData {
+ data: NonNull<u8>,
+ len: usize,
+ arena: *mut upb_Arena,
+}
+
+impl SerializedData {
+ pub unsafe fn from_raw_parts(arena: *mut upb_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 { upb_Arena_Free(self.arena) };
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_serialized_data_roundtrip() {
+ let arena = unsafe { upb_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");
+ }
+}
diff --git a/rust/test/BUILD b/rust/test/BUILD
index 95496f6..780d3c6 100644
--- a/rust/test/BUILD
+++ b/rust/test/BUILD
@@ -11,7 +11,10 @@
name = "unittest_proto_test",
srcs = ["unittest_proto_test.rs"],
# TODO(b/270274576): Enable testing on arm once we have a Rust Arm toolchain.
- tags = ["not_build:arm"],
+ tags = [
+ "not_build:arm",
+ "notsan",
+ ],
deps = [":unittest_rs_proto"],
)
@@ -41,7 +44,10 @@
name = "child_parent_test",
srcs = ["child_parent_test.rs"],
# TODO(b/270274576): Enable testing on arm once we have a Rust Arm toolchain.
- tags = ["not_build:arm"],
+ tags = [
+ "not_build:arm",
+ "notsan",
+ ],
deps = [
":child_rs_proto",
":parent_rs_proto",
diff --git a/rust/test/child_parent_test.rs b/rust/test/child_parent_test.rs
index 0bfb332..04e11e9 100644
--- a/rust/test/child_parent_test.rs
+++ b/rust/test/child_parent_test.rs
@@ -28,10 +28,21 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-fn main() {
- let _child = child_proto::Child {};
- let _parent = parent_proto::Parent {};
+#[test]
+fn test_canonical_types() {
+ let _child = child_proto::Child::new();
+ let _parent = parent_proto::Parent::new();
// Parent from child_proto crate should be the same type as Parent from
// parent_proto crate.
- let _parent_from_child: child_proto::Parent = parent_proto::Parent {};
+ let _parent_from_child: child_proto::Parent = parent_proto::Parent::new();
+}
+
+#[test]
+fn test_parent_serialization() {
+ assert_eq!(*parent_proto::Parent::new().serialize(), []);
+}
+
+#[test]
+fn test_child_serialization() {
+ assert_eq!(*child_proto::Child::new().serialize(), []);
}
diff --git a/rust/test/rust_proto_library_unit_test/empty.cc b/rust/test/rust_proto_library_unit_test/empty.cc
new file mode 100644
index 0000000..25d162f
--- /dev/null
+++ b/rust/test/rust_proto_library_unit_test/empty.cc
@@ -0,0 +1,33 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Test input file.
+
+int main() { return 0; }
\ No newline at end of file
diff --git a/rust/test/rust_proto_library_unit_test/empty.rs b/rust/test/rust_proto_library_unit_test/empty.rs
new file mode 100644
index 0000000..ed21cb5
--- /dev/null
+++ b/rust/test/rust_proto_library_unit_test/empty.rs
@@ -0,0 +1,33 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Test input file.
+
+fn main() {}
diff --git a/rust/test/rust_proto_library_unit_test/rust_proto_library_unit_test.bzl b/rust/test/rust_proto_library_unit_test/rust_proto_library_unit_test.bzl
index 6749cf9..5379207 100644
--- a/rust/test/rust_proto_library_unit_test/rust_proto_library_unit_test.bzl
+++ b/rust/test/rust_proto_library_unit_test/rust_proto_library_unit_test.bzl
@@ -2,6 +2,7 @@
load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts")
load(":defs.bzl", "ActionsInfo", "attach_aspect")
+load("//rust:defs.bzl", "RustProtoInfo")
def _find_action_with_mnemonic(actions, mnemonic):
action = [a for a in actions if a.mnemonic == mnemonic]
@@ -21,56 +22,58 @@
))
return input[0]
-####################################################################################################
-
-def _rust_compilation_action_has_runtime_as_input_test_impl(ctx):
- env = analysistest.begin(ctx)
- target_under_test = analysistest.target_under_test(env)
- actions = target_under_test[ActionsInfo].actions
- rustc_action = _find_action_with_mnemonic(actions, "Rustc")
- _find_rust_lib_input(rustc_action.inputs, "protobuf")
- asserts.true(env, rustc_action.outputs.to_list()[0].path.endswith(".rlib"))
-
- return analysistest.end(env)
-
-rust_compilation_action_has_runtime_as_input_test = analysistest.make(
- _rust_compilation_action_has_runtime_as_input_test_impl,
-)
-
-def _test_rust_compilation_action_has_runtime_as_input():
- native.proto_library(name = "some_proto", srcs = ["some_proto.proto"])
- attach_aspect(name = "some_proto_with_aspect", dep = ":some_proto")
-
- rust_compilation_action_has_runtime_as_input_test(
- name = "rust_compilation_action_has_runtime_as_input_test",
- target_under_test = ":some_proto_with_aspect",
- # TODO(b/270274576): Enable testing on arm once we have a Rust Arm toolchain.
- tags = ["not_build:arm"],
+def _relevant_linker_inputs(ltl):
+ return ltl.objects + ltl.pic_objects + (
+ [ltl.static_library] if ltl.static_library else []
+ ) + (
+ [ltl.pic_static_library] if ltl.pic_static_library else []
)
+def _find_linker_input(rust_proto_info, basename_substring):
+ cc_info = rust_proto_info.dep_variant_info.cc_info
+ for linker_input in cc_info.linking_context.linker_inputs.to_list():
+ for ltl in linker_input.libraries:
+ for file in _relevant_linker_inputs(ltl):
+ if basename_substring in file.basename:
+ return file
+
+ fail("Couldn't find file with suffix {} in {}".format(
+ basename_substring,
+ [
+ f.basename
+ for input in cc_info.linking_context.linker_inputs.to_list()
+ for ltl in input.libraries
+ for f in _relevant_linker_inputs(ltl)
+ ],
+ ))
+
####################################################################################################
-def _rust_compilation_action_has_deps_as_inputs_test_impl(ctx):
+def _rust_aspect_test_impl(ctx):
env = analysistest.begin(ctx)
target_under_test = analysistest.target_under_test(env)
actions = target_under_test[ActionsInfo].actions
rustc_action = _find_action_with_mnemonic(actions, "Rustc")
- _find_rust_lib_input(rustc_action.inputs, "parent")
+
+ # The action needs to have the Rust runtime as an input
+ _find_rust_lib_input(rustc_action.inputs, "protobuf")
+
+ # The action needs to produce a .rlib artifact (sometimes .rmeta as well, not tested here).
+ asserts.true(env, rustc_action.outputs.to_list()[0].path.endswith(".rlib"))
+
+ # The aspect needs to provide CcInfo that passes UPB gencode to the eventual linking.
+ _find_linker_input(target_under_test[RustProtoInfo], "child.upb.thunks")
+ _find_linker_input(target_under_test[RustProtoInfo], "parent.upb.thunks")
return analysistest.end(env)
-rust_compilation_action_has_deps_as_input_test = analysistest.make(
- _rust_compilation_action_has_deps_as_inputs_test_impl,
-)
+rust_aspect_test = analysistest.make(_rust_aspect_test_impl)
-def _test_rust_compilation_action_has_deps_as_input():
- native.proto_library(name = "parent_proto", srcs = ["parent.proto"])
- native.proto_library(name = "child_proto", srcs = ["child.proto"], deps = [":parent_proto"])
-
+def _test_aspect():
attach_aspect(name = "child_proto_with_aspect", dep = ":child_proto")
- rust_compilation_action_has_deps_as_input_test(
- name = "rust_compilation_action_has_deps_as_input_test",
+ rust_aspect_test(
+ name = "rust_aspect_test",
target_under_test = ":child_proto_with_aspect",
# TODO(b/270274576): Enable testing on arm once we have a Rust Arm toolchain.
tags = ["not_build:arm"],
@@ -83,13 +86,14 @@
Args:
name: name of the test suite"""
- _test_rust_compilation_action_has_runtime_as_input()
- _test_rust_compilation_action_has_deps_as_input()
+ native.proto_library(name = "parent_proto", srcs = ["parent.proto"])
+ native.proto_library(name = "child_proto", srcs = ["child.proto"], deps = [":parent_proto"])
+
+ _test_aspect()
native.test_suite(
name = name,
tests = [
- ":rust_compilation_action_has_runtime_as_input_test",
- ":rust_compilation_action_has_deps_as_input_test",
+ ":rust_aspect_test",
],
)
diff --git a/rust/test/unittest_proto_test.rs b/rust/test/unittest_proto_test.rs
index 24cad65..73807c8 100644
--- a/rust/test/unittest_proto_test.rs
+++ b/rust/test/unittest_proto_test.rs
@@ -28,8 +28,8 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-fn main() {
- // This is currently just a smoke test checking that we can generate gencode, compile it, and
- // link the test binary.
- let _test_all_types: unittest_proto::TestAllTypes;
+#[test]
+fn test_serialization() {
+ let test_all_types: unittest_proto::TestAllTypes = unittest_proto::TestAllTypes::new();
+ assert_eq!(*test_all_types.serialize(), []);
}
diff --git a/rust/upb_backend/BUILD b/rust/upb_backend/BUILD
new file mode 100644
index 0000000..d51328b
--- /dev/null
+++ b/rust/upb_backend/BUILD
@@ -0,0 +1,27 @@
+# This package contains Rust protobuf runtime implementation built on top of UPB.
+
+load("@rules_rust//rust:defs.bzl", "rust_library", "rust_test")
+
+rust_library(
+ name = "upb",
+ srcs = ["upb.rs"],
+ visibility = ["//src/google/protobuf:__subpackages__"],
+ deps = [":upb_c_api"],
+)
+
+rust_test(
+ name = "upb_test",
+ crate = ":upb",
+ tags = [
+ "not_build:arm",
+ "notsan",
+ ],
+)
+
+cc_library(
+ name = "upb_c_api",
+ srcs = ["upb_api.c"],
+ deps = [
+ "//third_party/upb",
+ ],
+)
diff --git a/rust/upb_backend/upb.rs b/rust/upb_backend/upb.rs
new file mode 100644
index 0000000..35a09fa
--- /dev/null
+++ b/rust/upb_backend/upb.rs
@@ -0,0 +1,53 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Rust bindings for UPB
+
+#[repr(C)]
+pub struct upb_Arena {
+ _data: [u8; 0],
+ _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
+}
+
+extern "C" {
+ pub fn upb_Arena_New() -> *mut upb_Arena;
+ pub fn upb_Arena_Free(arena: *mut upb_Arena);
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_arena_new_and_free() {
+ let arena = unsafe { upb_Arena_New() };
+ unsafe { upb_Arena_Free(arena) };
+ }
+}
diff --git a/rust/upb_backend/upb_api.c b/rust/upb_backend/upb_api.c
new file mode 100644
index 0000000..5b51fbf
--- /dev/null
+++ b/rust/upb_backend/upb_api.c
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2009-2021, Google LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Google LLC nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define UPB_BUILD_API
+
+#include "third_party/upb/upb/mem/arena.h" // IWYU pragma: keep
diff --git a/src/google/protobuf/compiler/rust/generator.cc b/src/google/protobuf/compiler/rust/generator.cc
index 08a14eb..171a2fb 100644
--- a/src/google/protobuf/compiler/rust/generator.cc
+++ b/src/google/protobuf/compiler/rust/generator.cc
@@ -89,15 +89,11 @@
// TODO(b/270138878): Remove `do_nothing` import once we have real logic. This
// is there only to smoke test rustc actions in rust_proto_library.
p.Emit(R"rs(
-#[allow(unused_imports)]
- use protobuf::do_nothing;
+ extern crate protobuf as __pb;
+ extern crate std as __std;
+
)rs");
- for (int i = 0; i < file->message_type_count(); ++i) {
- // TODO(b/270138878): Implement real logic
- p.Emit({{"Msg", file->message_type(i)->name()}}, R"rs(
- pub struct $Msg$ {}
- )rs");
- }
+
// TODO(b/270124215): Delete the following "placeholder impl" of `import
// public`. Also make sure to figure out how to map FileDescriptor#name to
// Rust crate names (currently Bazel labels).
@@ -114,6 +110,41 @@
}
}
+ for (int i = 0; i < file->message_type_count(); ++i) {
+ // TODO(b/270138878): Implement real logic
+ std::string full_name = file->message_type(i)->full_name();
+ absl::StrReplaceAll({{".", "_"}}, &full_name);
+ p.Emit({{"Msg", file->message_type(i)->name()}, {"pkg_Msg", full_name}},
+ R"rs(
+ pub struct $Msg$ {
+ msg: ::__std::ptr::NonNull<u8>,
+ arena: *mut ::__pb::upb_Arena,
+ }
+
+ impl $Msg$ {
+ pub fn new() -> $Msg$ {
+ let arena = unsafe { ::__pb::upb_Arena_New() };
+ let msg = unsafe { $pkg_Msg$_new(arena) };
+ $Msg$ { msg, arena }
+ }
+ pub fn serialize(&self) -> ::__pb::SerializedData {
+ let arena = unsafe { ::__pb::upb_Arena_New() };
+ let mut len = 0;
+ let chars = unsafe { $pkg_Msg$_serialize(self.msg, arena, &mut len) };
+ unsafe {::__pb::SerializedData::from_raw_parts(arena, chars, len)}
+ }
+ }
+
+ extern "C" {
+ fn $pkg_Msg$_new(arena: *mut ::__pb::upb_Arena) -> ::__std::ptr::NonNull<u8>;
+ fn $pkg_Msg$_serialize(
+ msg: ::__std::ptr::NonNull<u8>,
+ arena: *mut ::__pb::upb_Arena,
+ len: &mut usize) -> ::__std::ptr::NonNull<u8>;
+ }
+ )rs");
+ }
+
return true;
}