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)]