From 4c295b170fbfd3daf82fc7dafd7e0f0436e4a5af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?James=20=E2=80=98Twey=E2=80=99=20Kay?= Date: Tue, 14 Nov 2023 18:44:05 +0000 Subject: [PATCH 1/3] Simplify lifetimes Since `&'a mut R` is `Read` (or `Write`) when `R` is `Read` (resp. `Write`), there is no need to depend on ` &'a mut R` over just plain ` R`. The caller can still instantiate `R = &'a mut R_` when a reference is desired (and indeed this is done here for e.g. `MapDeserializer`). --- src/de.rs | 28 ++++++++--------- src/lib.rs | 4 +-- src/ser.rs | 83 +++++++++++++++++++++++++++----------------------- tests/serde.rs | 14 ++++----- 4 files changed, 68 insertions(+), 61 deletions(-) diff --git a/src/de.rs b/src/de.rs index 08534a2..8703412 100644 --- a/src/de.rs +++ b/src/de.rs @@ -143,8 +143,8 @@ struct Deserializer { max_remaining_depth: usize, } -impl<'de, R: Read> Deserializer> { - fn from_reader(input: &'de mut R, max_remaining_depth: usize) -> Self { +impl Deserializer> { + fn from_reader(input: R, max_remaining_depth: usize) -> Self { Deserializer { input: TeeReader::new(input), max_remaining_depth, @@ -152,10 +152,10 @@ impl<'de, R: Read> Deserializer> { } } -impl<'de> Deserializer<&'de [u8]> { +impl Deserializer { /// Creates a new `Deserializer` which will be deserializing the provided /// input. - fn new(input: &'de [u8], max_remaining_depth: usize) -> Self { + fn new(input: R, max_remaining_depth: usize) -> Self { Deserializer { input, max_remaining_depth, @@ -164,16 +164,16 @@ impl<'de> Deserializer<&'de [u8]> { } /// A reader that can optionally capture all bytes from an underlying [`Read`]er -struct TeeReader<'de, R> { +struct TeeReader { /// the underlying reader - reader: &'de mut R, + reader: R, /// If non-empty, all bytes read from the underlying reader will be captured in the last entry here. captured_keys: Vec>, } -impl<'de, R> TeeReader<'de, R> { +impl TeeReader { /// Wraps the provided reader in a new [`TeeReader`]. - pub fn new(reader: &'de mut R) -> Self { + pub fn new(reader: R) -> Self { Self { reader, captured_keys: Vec::new(), @@ -181,7 +181,7 @@ impl<'de, R> TeeReader<'de, R> { } } -impl<'de, R: Read> Read for TeeReader<'de, R> { +impl Read for TeeReader { fn read(&mut self, buf: &mut [u8]) -> std::io::Result { let bytes_read = self.reader.read(buf)?; if let Some(buffer) = self.captured_keys.last_mut() { @@ -289,7 +289,7 @@ trait BcsDeserializer<'de> { } } -impl<'de, R: Read> Deserializer> { +impl Deserializer> { fn parse_vec(&mut self) -> Result> { let len = self.parse_length()?; let mut output = vec![0; len]; @@ -303,7 +303,7 @@ impl<'de, R: Read> Deserializer> { } } -impl<'de, R: Read> BcsDeserializer<'de> for Deserializer> { +impl<'de, R: Read> BcsDeserializer<'de> for Deserializer> { type MaybeBorrowedBytes = Vec; fn fill_slice(&mut self, slice: &mut [u8]) -> Result<()> { @@ -428,7 +428,7 @@ impl Deserializer { } } -impl<'de, 'a, R> de::Deserializer<'de> for &'a mut Deserializer +impl<'de, R> de::Deserializer<'de> for &mut Deserializer where Deserializer: BcsDeserializer<'de>, { @@ -786,7 +786,7 @@ where } } -impl<'de, 'a, R> de::EnumAccess<'de> for &'a mut Deserializer +impl<'de, R> de::EnumAccess<'de> for &mut Deserializer where Deserializer: BcsDeserializer<'de>, { @@ -803,7 +803,7 @@ where } } -impl<'de, 'a, R> de::VariantAccess<'de> for &'a mut Deserializer +impl<'de, R> de::VariantAccess<'de> for &mut Deserializer where Deserializer: BcsDeserializer<'de>, { diff --git a/src/lib.rs b/src/lib.rs index 4ede21a..03925d6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,7 +12,7 @@ //! * provide good performance and concise (binary) representations; //! * support a rich set of data types commonly used in Rust; //! * enforce canonical serialization, meaning that every value of a given type should have -//! a single valid representation. +//! a single valid representation. //! //! BCS also aims to mitigate the consequence of malicious inputs by enforcing well-defined limits //! on large or nested containers during (de)serialization. @@ -44,7 +44,7 @@ //! applications must carefully plan in advance for adhoc extension points: //! * Enums may be used for explicit versioning and backward compatibility (e.g. extensible query interfaces). //! * In some cases, data fields of type `Vec` may also be added to allow (future) unknown payloads -//! in serialized form. +//! in serialized form. //! //! ## Detailed Specifications //! diff --git a/src/ser.rs b/src/ser.rs index 9bd42ce..a4e50d9 100644 --- a/src/ser.rs +++ b/src/ser.rs @@ -1,6 +1,11 @@ // Copyright (c) The Diem Core Contributors // SPDX-License-Identifier: Apache-2.0 +// `Error::other` doesn't exist on the MSRV. +#![allow(clippy::io_other_error)] +// And neither does `clippy::io_other_error`. +#![allow(unknown-lints)] + use crate::error::{Error, Result}; use serde::{ser, Serialize}; @@ -70,26 +75,28 @@ where } /// Same as `to_bytes` but write directly into an `std::io::Write` object. -pub fn serialize_into(write: &mut W, value: &T) -> Result<()> +pub fn serialize_into(mut write: impl std::io::Write, value: &T) -> Result<()> where - W: ?Sized + std::io::Write, T: ?Sized + Serialize, { - let serializer = Serializer::new(write, crate::MAX_CONTAINER_DEPTH); + let serializer = Serializer::new(&mut write, crate::MAX_CONTAINER_DEPTH); value.serialize(serializer) } /// Same as `serialize_into` but use `limit` as max container depth instead of MAX_CONTAINER_DEPTH /// Note that `limit` has to be lower than MAX_CONTAINER_DEPTH -pub fn serialize_into_with_limit(write: &mut W, value: &T, limit: usize) -> Result<()> +pub fn serialize_into_with_limit( + mut write: impl std::io::Write, + value: &T, + limit: usize, +) -> Result<()> where - W: ?Sized + std::io::Write, T: ?Sized + Serialize, { if limit > crate::MAX_CONTAINER_DEPTH { return Err(Error::NotSupported("limit exceeds the max allowed depth")); } - let serializer = Serializer::new(write, limit); + let serializer = Serializer::new(&mut write, limit); value.serialize(serializer) } @@ -140,17 +147,17 @@ pub fn is_human_readable() -> bool { } /// Serialization implementation for BCS -struct Serializer<'a, W: ?Sized> { - output: &'a mut W, +struct Serializer { + output: W, max_remaining_depth: usize, } -impl<'a, W> Serializer<'a, W> +impl Serializer where - W: ?Sized + std::io::Write, + W: std::io::Write, { /// Creates a new `Serializer` which will emit BCS. - fn new(output: &'a mut W, max_remaining_depth: usize) -> Self { + fn new(output: W, max_remaining_depth: usize) -> Self { Self { output, max_remaining_depth, @@ -190,9 +197,9 @@ where } } -impl<'a, W> ser::Serializer for Serializer<'a, W> +impl<'r, W> ser::Serializer for Serializer<&'r mut W> where - W: ?Sized + std::io::Write, + W: std::io::Write, { type Ok = (); type Error = Error; @@ -200,7 +207,7 @@ where type SerializeTuple = Self; type SerializeTupleStruct = Self; type SerializeTupleVariant = Self; - type SerializeMap = MapSerializer<'a, W>; + type SerializeMap = MapSerializer<&'r mut W>; type SerializeStruct = Self; type SerializeStructVariant = Self; @@ -403,9 +410,9 @@ where } } -impl<'a, W> ser::SerializeSeq for Serializer<'a, W> +impl ser::SerializeSeq for Serializer<&mut W> where - W: ?Sized + std::io::Write, + W: std::io::Write, { type Ok = (); type Error = Error; @@ -414,7 +421,7 @@ where where T: ?Sized + Serialize, { - value.serialize(Serializer::new(self.output, self.max_remaining_depth)) + value.serialize(Serializer::new(&mut *self.output, self.max_remaining_depth)) } fn end(self) -> Result<()> { @@ -422,9 +429,9 @@ where } } -impl<'a, W> ser::SerializeTuple for Serializer<'a, W> +impl ser::SerializeTuple for Serializer<&mut W> where - W: ?Sized + std::io::Write, + W: std::io::Write, { type Ok = (); type Error = Error; @@ -433,7 +440,7 @@ where where T: ?Sized + Serialize, { - value.serialize(Serializer::new(self.output, self.max_remaining_depth)) + value.serialize(Serializer::new(&mut *self.output, self.max_remaining_depth)) } fn end(self) -> Result<()> { @@ -441,9 +448,9 @@ where } } -impl<'a, W> ser::SerializeTupleStruct for Serializer<'a, W> +impl ser::SerializeTupleStruct for Serializer<&mut W> where - W: ?Sized + std::io::Write, + W: std::io::Write, { type Ok = (); type Error = Error; @@ -452,7 +459,7 @@ where where T: ?Sized + Serialize, { - value.serialize(Serializer::new(self.output, self.max_remaining_depth)) + value.serialize(Serializer::new(&mut *self.output, self.max_remaining_depth)) } fn end(self) -> Result<()> { @@ -460,9 +467,9 @@ where } } -impl<'a, W> ser::SerializeTupleVariant for Serializer<'a, W> +impl ser::SerializeTupleVariant for Serializer<&mut W> where - W: ?Sized + std::io::Write, + W: std::io::Write, { type Ok = (); type Error = Error; @@ -471,7 +478,7 @@ where where T: ?Sized + Serialize, { - value.serialize(Serializer::new(self.output, self.max_remaining_depth)) + value.serialize(Serializer::new(&mut *self.output, self.max_remaining_depth)) } fn end(self) -> Result<()> { @@ -480,14 +487,14 @@ where } #[doc(hidden)] -struct MapSerializer<'a, W: ?Sized> { - serializer: Serializer<'a, W>, +pub struct MapSerializer { + serializer: Serializer, entries: Vec<(Vec, Vec)>, next_key: Option>, } -impl<'a, W: ?Sized> MapSerializer<'a, W> { - fn new(serializer: Serializer<'a, W>) -> Self { +impl MapSerializer { + fn new(serializer: Serializer) -> Self { MapSerializer { serializer, entries: Vec::new(), @@ -496,9 +503,9 @@ impl<'a, W: ?Sized> MapSerializer<'a, W> { } } -impl<'a, W> ser::SerializeMap for MapSerializer<'a, W> +impl ser::SerializeMap for MapSerializer where - W: ?Sized + std::io::Write, + W: std::io::Write, { type Ok = (); type Error = Error; @@ -557,9 +564,9 @@ where } } -impl<'a, W> ser::SerializeStruct for Serializer<'a, W> +impl ser::SerializeStruct for Serializer<&mut W> where - W: ?Sized + std::io::Write, + W: std::io::Write, { type Ok = (); type Error = Error; @@ -568,7 +575,7 @@ where where T: ?Sized + Serialize, { - value.serialize(Serializer::new(self.output, self.max_remaining_depth)) + value.serialize(Serializer::new(&mut *self.output, self.max_remaining_depth)) } fn end(self) -> Result<()> { @@ -576,9 +583,9 @@ where } } -impl<'a, W> ser::SerializeStructVariant for Serializer<'a, W> +impl ser::SerializeStructVariant for Serializer<&mut W> where - W: ?Sized + std::io::Write, + W: std::io::Write, { type Ok = (); type Error = Error; @@ -587,7 +594,7 @@ where where T: ?Sized + Serialize, { - value.serialize(Serializer::new(self.output, self.max_remaining_depth)) + value.serialize(Serializer::new(&mut *self.output, self.max_remaining_depth)) } fn end(self) -> Result<()> { diff --git a/tests/serde.rs b/tests/serde.rs index 8305f61..fa1c7f5 100644 --- a/tests/serde.rs +++ b/tests/serde.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 // For some reason deriving `Arbitrary` results in clippy firing a `unit_arg` violation -#![allow(clippy::unit_arg)] +#![allow(clippy::unit_arg, non_local_definitions)] use std::{ collections::{BTreeMap, BTreeSet, HashMap}, @@ -516,7 +516,7 @@ fn cow() { #[derive(Serialize, Deserialize, Debug)] enum Message<'a> { - M1(Cow<'a, Vec>), + M1(Cow<'a, [u32]>), M2(Cow<'a, BTreeMap>), } @@ -562,10 +562,10 @@ fn strbox() { let strx: &'static str = "hello world"; let serialized = to_bytes(&Cow::Borrowed(strx)).unwrap(); - let deserialized: Cow<'static, String> = from_bytes(&serialized).unwrap(); + let deserialized: Cow<'static, str> = from_bytes(&serialized).unwrap(); let stringx: String = deserialized.into_owned(); assert_eq!(strx, stringx); - let deserialized: Cow<'static, String> = from_bytes_via_reader(&serialized).unwrap(); + let deserialized: Cow<'static, str> = from_bytes_via_reader(&serialized).unwrap(); let stringx: String = deserialized.into_owned(); assert_eq!(strx, stringx); } @@ -576,7 +576,7 @@ fn slicebox() { let slice = [1u32, 2, 3, 4, 5]; let serialized = to_bytes(&Cow::Borrowed(&slice[..])).unwrap(); - let deserialized: Cow<'static, Vec> = from_bytes(&serialized).unwrap(); + let deserialized: Cow<'static, [u32]> = from_bytes(&serialized).unwrap(); { let sb: &[u32] = &deserialized; assert_eq!(slice, sb); @@ -584,7 +584,7 @@ fn slicebox() { let vecx: Vec = deserialized.into_owned(); assert_eq!(slice, vecx[..]); - let deserialized: Cow<'static, Vec> = from_bytes_via_reader(&serialized).unwrap(); + let deserialized: Cow<'static, [u32]> = from_bytes_via_reader(&serialized).unwrap(); { let sb: &[u32] = &deserialized; assert_eq!(slice, sb); @@ -641,7 +641,7 @@ fn serde_known_vector() { map.insert(vec![20, 21, 89, 105], vec![201, 23, 90]); let f = Foo { - a: u64::max_value(), + a: u64::MAX, b: vec![100, 99, 88, 77, 66, 55], c: b, d: true, From dc996e2618b25d7c97ce5575e35dc21b1cff4e4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?James=20=E2=80=98Twey=E2=80=99=20Kay?= Date: Fri, 13 Jun 2025 13:37:33 +0100 Subject: [PATCH 2/3] Follow lifetime naming conventions --- src/ser.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ser.rs b/src/ser.rs index a4e50d9..abc39fa 100644 --- a/src/ser.rs +++ b/src/ser.rs @@ -197,7 +197,7 @@ where } } -impl<'r, W> ser::Serializer for Serializer<&'r mut W> +impl<'a, W> ser::Serializer for Serializer<&'a mut W> where W: std::io::Write, { @@ -207,7 +207,7 @@ where type SerializeTuple = Self; type SerializeTupleStruct = Self; type SerializeTupleVariant = Self; - type SerializeMap = MapSerializer<&'r mut W>; + type SerializeMap = MapSerializer<&'a mut W>; type SerializeStruct = Self; type SerializeStructVariant = Self; From a2260bfd5efef521c03b05eae2a86d572fa5d02a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?James=20=E2=80=98Twey=E2=80=99=20Kay?= Date: Fri, 13 Jun 2025 13:37:47 +0100 Subject: [PATCH 3/3] Fix lint name --- src/ser.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ser.rs b/src/ser.rs index abc39fa..0ce3ae9 100644 --- a/src/ser.rs +++ b/src/ser.rs @@ -4,7 +4,7 @@ // `Error::other` doesn't exist on the MSRV. #![allow(clippy::io_other_error)] // And neither does `clippy::io_other_error`. -#![allow(unknown-lints)] +#![allow(unknown_lints)] use crate::error::{Error, Result}; use serde::{ser, Serialize};