diff --git a/Cargo.toml b/Cargo.toml index 8b17aa75..4e3bde9c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -62,7 +62,8 @@ bytes = "1.11" static_assertions = "1.1" thiserror = "2.0.9" # cdr-encoding = { path = "../cdr-encoding"} -cdr-encoding = { version="0.10" } +# cdr-encoding = { version="0.10" } +cdr-encoding = { git = "https://github.com/iblnkn/cdr-encoding/", branch="zero-copy-byte-deserialization" } cdr-encoding-size = { version="^0.5" } futures = "0.3" io-extras = "0.18.0" @@ -118,4 +119,4 @@ termion = "4.0.2" [target.'cfg(target_os = "linux")'.dev-dependencies] -procfs = "0.17" # for ddsperf \ No newline at end of file +procfs = "0.17" # for ddsperf diff --git a/src/dds/adapters.rs b/src/dds/adapters.rs index 3e1032d7..5d044a9f 100644 --- a/src/dds/adapters.rs +++ b/src/dds/adapters.rs @@ -125,13 +125,17 @@ pub mod no_key { /// /// `encoding` must be something given by `supported_encodings()`, or /// implementation may fail with Err or `panic!()`. - fn from_bytes_with( - input_bytes: &[u8], + /// + /// The input slice's lifetime is tied to the deserialization lifetime + /// `'de`, so adapters that produce borrowed data (zero-copy) are + /// supported. + fn from_bytes_with<'de, S>( + input_bytes: &'de [u8], encoding: RepresentationIdentifier, decoder: S, ) -> Result where - S: Decode, + S: Decode<'de, Self::Decoded>, { decoder .decode_bytes(input_bytes, encoding) @@ -158,8 +162,9 @@ pub mod no_key { /// Type of the default decoder. /// /// The default decoder needs to be clonable to be usable for async stream - /// creation (as it's needed multiple times). - type Decoder: Decode + Clone; + /// creation (as it's needed multiple times). It must work for any input + /// lifetime, hence the higher-ranked `for<'de>` bound. + type Decoder: for<'de> Decode<'de, Self::Decoded, Error = Self::Error> + Clone; /// The default decoder value. /// @@ -168,21 +173,23 @@ pub mod no_key { const DECODER: Self::Decoder; } - /// The trait `Decode` defines a decoder object that produced a value of type - /// `Dec` from a slice of bytes and a [`RepresentationIdentifier`]. + /// The trait `Decode` defines a decoder object that produces a value of type + /// `Decoded` from a slice of bytes and a [`RepresentationIdentifier`]. + /// + /// Note that `Decoded` maps to associated type `Decoded` in + /// `DeserializerAdapter`, not `D`. /// - /// Note - /// that `Decoded` maps to associated type `Decoded` in - /// `DeserializerAdapter` , not `D`. - pub trait Decode { + /// The lifetime `'de` is the deserialization lifetime: the returned + /// `Decoded` value may borrow from `input_bytes` for `'de`. + pub trait Decode<'de, Decoded> { /// The decoding error type returned by [`Self::decode_bytes`]. type Error: std::error::Error; - /// Tries to decode the given byte slice to a value of type `D` using the - /// given encoding. + /// Tries to decode the given byte slice to a value of type `Decoded` + /// using the given encoding. fn decode_bytes( self, - input_bytes: &[u8], + input_bytes: &'de [u8], encoding: RepresentationIdentifier, ) -> Result; } @@ -242,13 +249,13 @@ pub mod with_key { /// /// `encoding` must be something given by `supported_encodings()`, or /// implementation may fail with Err or `panic!()`. - fn key_from_bytes_with( - input_bytes: &[u8], + fn key_from_bytes_with<'de, S>( + input_bytes: &'de [u8], encoding: RepresentationIdentifier, decoder: S, ) -> Result where - S: Decode, + S: Decode<'de, Self::Decoded, Self::DecodedKey>, { decoder .decode_key_bytes(input_bytes, encoding) @@ -280,8 +287,9 @@ pub mod with_key { /// Type of the default decoder. /// /// The default decoder needs to be clonable to be usable for async stream - /// creation (as it's needed multiple times). - type Decoder: Decode + Clone; + /// creation (as it's needed multiple times). It must work for any input + /// lifetime, hence the higher-ranked `for<'de>` bound. + type Decoder: for<'de> Decode<'de, Self::Decoded, Self::DecodedKey, Error = Self::Error> + Clone; /// The default decoder value. /// @@ -290,15 +298,18 @@ pub mod with_key { const DECODER: Self::Decoder; } - /// Decodes a value of type `Dec` from a slice of bytes and a - /// [`RepresentationIdentifier`]. Note that `Dec` maps to associated type - /// `Decoded` in `DeserializerAdapter` , not `D`. - pub trait Decode: no_key::Decode { - /// Tries to decode the given byte slice to a value of type `D` using the - /// given encoding. + /// Decodes a value of type `Dec` (or its key `DecKey`) from a slice of + /// bytes and a [`RepresentationIdentifier`]. Note that `Dec` maps to + /// associated type `Decoded` in `DeserializerAdapter`, not `D`. + /// + /// The lifetime `'de` is the deserialization lifetime: the returned key + /// may borrow from `input_key_bytes` for `'de`. + pub trait Decode<'de, Dec, DecKey>: no_key::Decode<'de, Dec> { + /// Tries to decode the given byte slice to a value of type `DecKey` + /// using the given encoding. fn decode_key_bytes( self, - input_key_bytes: &[u8], + input_key_bytes: &'de [u8], encoding: RepresentationIdentifier, ) -> Result; } diff --git a/src/dds/no_key/simpledatareader.rs b/src/dds/no_key/simpledatareader.rs index 0825ad71..f695e97a 100644 --- a/src/dds/no_key/simpledatareader.rs +++ b/src/dds/no_key/simpledatareader.rs @@ -64,7 +64,7 @@ where pub fn try_take_one_with(&self, decoder: S) -> ReadResult>> where - S: Decode + Clone, + S: for<'de> Decode<'de, DA::Decoded, Error = DA::Error> + Clone, { match self .keyed_simpledatareader @@ -101,7 +101,7 @@ where decoder: S, ) -> impl FusedStream>> + 'a where - S: Decode + Clone + 'a, + S: for<'de> Decode<'de, DA::Decoded, Error = DA::Error> + Clone + 'a, { self .keyed_simpledatareader diff --git a/src/dds/no_key/wrappers.rs b/src/dds/no_key/wrappers.rs index 6245ca5a..dda4d792 100644 --- a/src/dds/no_key/wrappers.rs +++ b/src/dds/no_key/wrappers.rs @@ -144,15 +144,15 @@ impl DecodeWrapper { // re-implement no_key::Decode for the wrapper also. Wrapped type // already does it for us. -impl no_key::Decode for DecodeWrapper +impl<'de, Decoded, NoKeyDecode> no_key::Decode<'de, Decoded> for DecodeWrapper where - NoKeyDecode: no_key::Decode, + NoKeyDecode: no_key::Decode<'de, Decoded>, { type Error = NoKeyDecode::Error; fn decode_bytes( self, - input_bytes: &[u8], + input_bytes: &'de [u8], encoding: RepresentationIdentifier, ) -> Result { self.no_key.decode_bytes(input_bytes, encoding) @@ -162,13 +162,13 @@ where // implement with_key::Decode for the wrapper. // The key has type `()`, so the decoded value is always `()` regardless of the // input bytes. -impl with_key::Decode for DecodeWrapper +impl<'de, Decoded, NoKeyDecode> with_key::Decode<'de, Decoded, ()> for DecodeWrapper where - NoKeyDecode: no_key::Decode, + NoKeyDecode: no_key::Decode<'de, Decoded>, { fn decode_key_bytes( self, - _input_key_bytes: &[u8], + _input_key_bytes: &'de [u8], _encoding: RepresentationIdentifier, ) -> Result<(), Self::Error> { Ok(()) diff --git a/src/dds/with_key/simpledatareader.rs b/src/dds/with_key/simpledatareader.rs index 0c6c0e4e..6bf345ba 100644 --- a/src/dds/with_key/simpledatareader.rs +++ b/src/dds/with_key/simpledatareader.rs @@ -234,7 +234,7 @@ where decoder: S, ) -> ReadResult> where - S: Decode, + S: for<'de> Decode<'de, DA::Decoded, DA::DecodedKey, Error = DA::Error>, { match cc.data_value { DDSData::Data { @@ -342,7 +342,7 @@ where #[allow(clippy::needless_pass_by_value)] pub fn try_take_one_with(&self, decoder: S) -> ReadResult>> where - S: Decode + Clone, + S: for<'de> Decode<'de, DA::Decoded, DA::DecodedKey, Error = DA::Error> + Clone, { let is_reliable = matches!( self.qos_policy.reliability(), @@ -414,14 +414,14 @@ where where DA: DefaultDecoder, DA::Decoder: Clone, - S: Decode, + S: for<'de> Decode<'de, DA::Decoded, DA::DecodedKey, Error = DA::Error>, { Self::as_async_stream_with(self, DA::DECODER) } pub fn as_async_stream_with(&self, decoder: S) -> SimpleDataReaderStream<'_, D, S, DA> where - S: Decode + Clone, + S: for<'de> Decode<'de, DA::Decoded, DA::DecodedKey, Error = DA::Error> + Clone, { SimpleDataReaderStream { simple_datareader: self, @@ -553,7 +553,7 @@ where pub struct SimpleDataReaderStream< 'a, D: Keyed + 'static, - S: Decode, + S: for<'de> Decode<'de, DA::Decoded, DA::DecodedKey, Error = DA::Error>, DA: DeserializerAdapter + 'static = CDRDeserializerAdapter, > { simple_datareader: &'a SimpleDataReader, @@ -568,7 +568,7 @@ impl Unpin for SimpleDataReaderStream<'_, D, S, DA> where D: Keyed + 'static, DA: DeserializerAdapter, - S: Decode + Unpin, + S: for<'de> Decode<'de, DA::Decoded, DA::DecodedKey, Error = DA::Error> + Unpin, { } @@ -576,7 +576,7 @@ impl Stream for SimpleDataReaderStream<'_, D, S, DA> where D: Keyed + 'static, DA: DeserializerAdapter, - S: Decode + Clone, + S: for<'de> Decode<'de, DA::Decoded, DA::DecodedKey, Error = DA::Error> + Clone, { type Item = ReadResult>; @@ -633,7 +633,7 @@ impl FusedStream for SimpleDataReaderStream<'_, D, S, DA> where D: Keyed + 'static, DA: DeserializerAdapter, - S: Decode + Clone, + S: for<'de> Decode<'de, DA::Decoded, DA::DecodedKey, Error = DA::Error> + Clone, { fn is_terminated(&self) -> bool { false // Never terminate. This means it is always valid to call poll_next(). diff --git a/src/serialization/cdr_adapters.rs b/src/serialization/cdr_adapters.rs index cd9221b3..2c329ebc 100644 --- a/src/serialization/cdr_adapters.rs +++ b/src/serialization/cdr_adapters.rs @@ -135,11 +135,12 @@ where } } -/// A default decoder is available for all types that implement -/// `serde::Deserialize`. -impl<'de, D> no_key::DefaultDecoder for CDRDeserializerAdapter +/// A default decoder is available for all owned types that implement +/// `serde::Deserialize`. Borrowing types use `from_bytes_with` with an +/// explicit decoder instead. +impl no_key::DefaultDecoder for CDRDeserializerAdapter where - D: serde::Deserialize<'de>, + D: DeserializeOwned, { type Decoder = CdrDeserializeDecoder; const DECODER: Self::Decoder = CdrDeserializeDecoder(PhantomData); @@ -157,25 +158,25 @@ where /// Decode type based on a `serde::Deserialize` implementation. pub struct CdrDeserializeDecoder(PhantomData); -impl<'de, D> no_key::Decode for CdrDeserializeDecoder +impl<'de, D> no_key::Decode<'de, D> for CdrDeserializeDecoder where D: serde::Deserialize<'de>, { type Error = Error; - fn decode_bytes(self, input_bytes: &[u8], encoding: RepresentationIdentifier) -> Result { + fn decode_bytes(self, input_bytes: &'de [u8], encoding: RepresentationIdentifier) -> Result { deserialize_from_cdr_with_decoder_and_rep_id(input_bytes, encoding, PhantomData).map(|r| r.0) } } -impl with_key::Decode for CdrDeserializeDecoder +impl<'de, Dec, DecKey> with_key::Decode<'de, Dec, DecKey> for CdrDeserializeDecoder where - Dec: DeserializeOwned, - DecKey: DeserializeOwned, + Dec: serde::Deserialize<'de>, + DecKey: serde::Deserialize<'de>, { fn decode_key_bytes( self, - input_key_bytes: &[u8], + input_key_bytes: &'de [u8], encoding: RepresentationIdentifier, ) -> Result { deserialize_from_cdr_with_decoder_and_rep_id(input_key_bytes, encoding, PhantomData) @@ -210,26 +211,27 @@ where } /// Decode type based on a [`serde::de::DeserializeSeed`]-based decoder. -impl<'de, D, S, SK> no_key::Decode for CdrDeserializeSeedDecoder +impl<'de, D, S, SK> no_key::Decode<'de, D> for CdrDeserializeSeedDecoder where S: serde::de::DeserializeSeed<'de, Value = D>, { type Error = Error; - fn decode_bytes(self, input_bytes: &[u8], encoding: RepresentationIdentifier) -> Result { + fn decode_bytes(self, input_bytes: &'de [u8], encoding: RepresentationIdentifier) -> Result { deserialize_from_cdr_with_decoder_and_rep_id(input_bytes, encoding, self.value_seed) .map(|r| r.0) } } -impl<'de, Dec, DecKey, S, SK> with_key::Decode for CdrDeserializeSeedDecoder +impl<'de, Dec, DecKey, S, SK> with_key::Decode<'de, Dec, DecKey> + for CdrDeserializeSeedDecoder where S: serde::de::DeserializeSeed<'de, Value = Dec>, SK: serde::de::DeserializeSeed<'de, Value = DecKey>, { fn decode_key_bytes( self, - input_key_bytes: &[u8], + input_key_bytes: &'de [u8], encoding: RepresentationIdentifier, ) -> Result { deserialize_from_cdr_with_decoder_and_rep_id(input_key_bytes, encoding, self.key_seed) @@ -241,7 +243,7 @@ where /// /// Returns deserialized object. Byte count is discarded. pub fn deserialize_from_cdr_with_rep_id<'de, T>( - input_bytes: &[u8], + input_bytes: &'de [u8], encoding: RepresentationIdentifier, ) -> Result<(T, usize)> where @@ -254,7 +256,7 @@ where /// /// Returns deserialized object and byte count of stream consumed. pub fn deserialize_from_cdr_with_decoder_and_rep_id<'de, S>( - input_bytes: &[u8], + input_bytes: &'de [u8], encoding: RepresentationIdentifier, decoder: S, ) -> Result<(S::Value, usize)> diff --git a/src/serialization/pl_cdr_adapters.rs b/src/serialization/pl_cdr_adapters.rs index c3207179..08d7303c 100644 --- a/src/serialization/pl_cdr_adapters.rs +++ b/src/serialization/pl_cdr_adapters.rs @@ -167,7 +167,7 @@ where /// Decode type based on [`PlCdrDeserialize`] implementation. pub struct PlCdrDeserializer(PhantomData); -impl no_key::Decode for PlCdrDeserializer +impl<'de, D> no_key::Decode<'de, D> for PlCdrDeserializer where D: PlCdrDeserialize, { @@ -175,7 +175,7 @@ where fn decode_bytes( self, - input_bytes: &[u8], + input_bytes: &'de [u8], encoding: RepresentationIdentifier, ) -> Result { match encoding { @@ -189,14 +189,14 @@ where } } -impl with_key::Decode for PlCdrDeserializer +impl<'de, Dec, DecKey> with_key::Decode<'de, Dec, DecKey> for PlCdrDeserializer where Dec: PlCdrDeserialize, DecKey: PlCdrDeserialize, { fn decode_key_bytes( self, - input_bytes: &[u8], + input_bytes: &'de [u8], encoding: RepresentationIdentifier, ) -> Result { match encoding {