From 6d25846f4718c37629d8f6df9a5534690da5c498 Mon Sep 17 00:00:00 2001 From: Protobuf Team Bot Date: Mon, 22 Jul 2024 09:39:02 -0700 Subject: [PATCH] Add 'specific' traits for common gencode message operations. This also changes MessageView and MessageMut to be subtraits of the ViewProxy and MutProxy (which also requires them to have lifetimes now, and a weird extra bounds on ViewProxy) PiperOrigin-RevId: 654788207 --- conformance/conformance_rust.rs | 52 +++++-------- rust/codegen_traits.rs | 80 +++++++++++++++++++- rust/shared.rs | 7 +- src/google/protobuf/compiler/rust/message.cc | 44 +++++++++-- 4 files changed, 141 insertions(+), 42 deletions(-) diff --git a/conformance/conformance_rust.rs b/conformance/conformance_rust.rs index adfe8578ab..bbb0710970 100644 --- a/conformance/conformance_rust.rs +++ b/conformance/conformance_rust.rs @@ -13,6 +13,7 @@ use protobuf_cpp as kernel; use protobuf_upb as kernel; use kernel::Optional::{Set, Unset}; +use kernel::{Message, ParseError}; use std::io::{self, ErrorKind, Read, Write}; use test_messages_edition2023_rust_proto::TestAllTypesEdition2023; @@ -73,52 +74,39 @@ fn do_test(req: &ConformanceRequest) -> ConformanceResponse { Set(bytes) => bytes, }; + fn roundtrip(bytes: &[u8]) -> Result, ParseError> { + T::parse(bytes).map(|msg| msg.serialize().unwrap()) + } + let serialized = match message_type.as_bytes() { b"protobuf_test_messages.proto2.TestAllTypesProto2" => { - if let Ok(msg) = TestAllTypesProto2::parse(bytes) { - msg.serialize().unwrap() - } else { - resp.set_parse_error("failed to parse bytes"); - return resp; - } + roundtrip::(bytes) } b"protobuf_test_messages.proto3.TestAllTypesProto3" => { - if let Ok(msg) = TestAllTypesProto3::parse(bytes) { - msg.serialize().unwrap() - } else { - resp.set_parse_error("failed to parse bytes"); - return resp; - } + roundtrip::(bytes) } b"protobuf_test_messages.editions.TestAllTypesEdition2023" => { - if let Ok(msg) = TestAllTypesEdition2023::parse(bytes) { - msg.serialize().unwrap() - } else { - resp.set_parse_error("failed to parse bytes"); - return resp; - } + roundtrip::(bytes) } b"protobuf_test_messages.editions.proto2.TestAllTypesProto2" => { - if let Ok(msg) = EditionsTestAllTypesProto2::parse(bytes) { - msg.serialize().unwrap() - } else { - resp.set_parse_error("failed to parse bytes"); - return resp; - } + roundtrip::(bytes) } b"protobuf_test_messages.editions.proto3.TestAllTypesProto3" => { - if let Ok(msg) = EditionsTestAllTypesProto3::parse(bytes) { - msg.serialize().unwrap() - } else { - resp.set_parse_error("failed to parse bytes"); - return resp; - } + roundtrip::(bytes) } _ => panic!("unexpected msg type {message_type}"), }; - resp.set_protobuf_payload(serialized); - return resp; + match serialized { + Ok(serialized) => { + resp.set_protobuf_payload(serialized); + } + Err(_) => { + resp.set_parse_error("failed to parse bytes"); + } + } + + resp } fn main() { diff --git a/rust/codegen_traits.rs b/rust/codegen_traits.rs index 89c2db871d..fe5de9916b 100644 --- a/rust/codegen_traits.rs +++ b/rust/codegen_traits.rs @@ -7,11 +7,83 @@ //! Traits that are implemeted by codegen types. -use crate::Proxied; +use crate::{MutProxied, MutProxy, ViewProxy}; +use create::Parse; +use read::Serialize; use std::fmt::Debug; +use write::ClearAndParse; -pub trait Message: Default + Debug + Proxied + Send + Sync {} +/// A trait that all generated owned message types implement. +pub trait Message: MutProxied + // Create traits: + + create::Parse + Default + // Read traits: + + Debug + Serialize + // Write traits: + // TODO: Msg should impl Clear. + + ClearAndParse + // Thread safety: + + Send + Sync + // Copy/Clone: + + Clone + {} -pub trait MessageView: Debug + Send + Sync {} +/// A trait that all generated message views implement. +pub trait MessageView<'msg>: ViewProxy<'msg, Proxied = Self::Message> + // Read traits: + + Debug + Serialize + // Thread safety: + + Send + Sync + // Copy/Clone: + + Copy + Clone + { + #[doc(hidden)] + type Message: Message; + } -pub trait MessageMut: Debug + Sync {} +/// A trait that all generated message muts implement. +pub trait MessageMut<'msg>: + MutProxy<'msg, Proxied = Self::Message> + // Read traits: + + Debug + Serialize + // Write traits: + // TODO: MsgMut should impl Clear and ClearAndParse. + // Thread safety: + + Sync + // Copy/Clone: (Neither) +{ + #[doc(hidden)] + type Message: Message; +} + +/// Operations related to constructing a message. Only owned messages implement +/// these traits. +pub(crate) mod create { + + pub trait Parse: Sized { + fn parse(serialized: &[u8]) -> Result; + } +} + +/// Operations related to reading some aspect of a message (methods that would +/// have a `&self` receiver on an owned message). Owned messages, views, and +/// muts all implement these traits. +pub(crate) mod read { + pub trait Serialize { + fn serialize(&self) -> Result, crate::SerializeError>; + } +} + +/// Operations related to mutating a message (methods that would have a `&mut +/// self` receiver on an owned message). Owned messages and muts implement these +/// traits. +pub(crate) mod write { + + pub trait Clear { + fn clear(&mut self); + } + + pub trait ClearAndParse { + fn clear_and_parse(&mut self, data: &[u8]) -> Result<(), crate::ParseError>; + } +} diff --git a/rust/shared.rs b/rust/shared.rs index ec31d65a01..113292c875 100644 --- a/rust/shared.rs +++ b/rust/shared.rs @@ -22,7 +22,12 @@ use std::fmt; /// These are the items protobuf users can access directly. #[doc(hidden)] pub mod __public { - pub use crate::codegen_traits::{Message, MessageMut, MessageView}; + pub use crate::codegen_traits::{ + create::Parse, + read::Serialize, + write::{Clear, ClearAndParse}, + Message, MessageMut, MessageView, + }; pub use crate::r#enum::{Enum, UnknownEnumValue}; pub use crate::map::{Map, MapIter, MapMut, MapView, ProxiedInMapValue}; pub use crate::optional::Optional; diff --git a/src/google/protobuf/compiler/rust/message.cc b/src/google/protobuf/compiler/rust/message.cc index 20217a1ae5..d18ece8348 100644 --- a/src/google/protobuf/compiler/rust/message.cc +++ b/src/google/protobuf/compiler/rust/message.cc @@ -953,15 +953,33 @@ void GenerateRs(Context& ctx, const Descriptor& msg) { impl $pb$::Message for $Msg$ {} + impl std::default::Default for $Msg$ { + fn default() -> Self { + Self::new() + } + } + + impl $pb$::Parse for $Msg$ { + fn parse(serialized: &[u8]) -> Result { + Self::parse(serialized) + } + } + impl std::fmt::Debug for $Msg$ { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { $Msg::debug$ } } - impl std::default::Default for $Msg$ { - fn default() -> Self { - Self::new() + impl $pb$::Serialize for $Msg$ { + fn serialize(&self) -> Result, $pb$::SerializeError> { + self.serialize() + } + } + + impl $pb$::ClearAndParse for $Msg$ { + fn clear_and_parse(&mut self, data: &[u8]) -> Result<(), $pb$::ParseError> { + self.clear_and_parse(data) } } @@ -990,7 +1008,9 @@ void GenerateRs(Context& ctx, const Descriptor& msg) { _phantom: $Phantom$<&'msg ()>, } - impl $pb$::MessageView for $Msg$View<'_> {} + impl<'msg> $pb$::MessageView<'msg> for $Msg$View<'msg> { + type Message = $Msg$; + } impl std::fmt::Debug for $Msg$View<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -998,6 +1018,12 @@ void GenerateRs(Context& ctx, const Descriptor& msg) { } } + impl $pb$::Serialize for $Msg$View<'_> { + fn serialize(&self) -> Result, $pb$::SerializeError> { + self.serialize() + } + } + #[allow(dead_code)] impl<'msg> $Msg$View<'msg> { #[doc(hidden)] @@ -1053,7 +1079,9 @@ void GenerateRs(Context& ctx, const Descriptor& msg) { inner: $pbr$::MutatorMessageRef<'msg>, } - impl $pb$::MessageMut for $Msg$Mut<'_> {} + impl<'msg> $pb$::MessageMut<'msg> for $Msg$Mut<'msg> { + type Message = $Msg$; + } impl std::fmt::Debug for $Msg$Mut<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -1061,6 +1089,12 @@ void GenerateRs(Context& ctx, const Descriptor& msg) { } } + impl $pb$::Serialize for $Msg$Mut<'_> { + fn serialize(&self) -> Result, $pb$::SerializeError> { + self.serialize() + } + } + #[allow(dead_code)] impl<'msg> $Msg$Mut<'msg> { #[doc(hidden)]