diff --git a/Cargo.toml b/Cargo.toml index 5f4fd2c..90dd3da 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,11 @@ version = "1.0" optional = true default-features = false +[dependencies.serde_with] +version = "3" +optional = true +default-features = false + [dependencies.zeroize] version = "1.4" optional = true @@ -30,6 +35,7 @@ version = "1.0" [dev-dependencies] matches = { version = "0.1" } bencher = "0.1.4" +serde_with = { version = "3" } [[bench]] name = "extend" @@ -42,6 +48,7 @@ harness = false [features] default = ["std"] std = [] +serde = ["dep:serde", "dep:serde_with"] [profile.bench] debug = true diff --git a/src/arrayvec.rs b/src/arrayvec.rs index 37e151a..007980d 100644 --- a/src/arrayvec.rs +++ b/src/arrayvec.rs @@ -17,8 +17,11 @@ use std::io; use std::mem::ManuallyDrop; use std::mem::MaybeUninit; -#[cfg(feature="serde")] -use serde::{Serialize, Deserialize, Serializer, Deserializer}; +#[cfg(feature = "serde")] +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + +#[cfg(feature = "serde")] +use serde_with::{de::DeserializeAsWrap, ser::SerializeAsWrap, DeserializeAs, SerializeAs}; use crate::LenUint; use crate::errors::CapacityError; @@ -1262,7 +1265,18 @@ impl Serialize for ArrayVec { } } -#[cfg(feature="serde")] +#[cfg(feature = "serde")] +/// Requires crate feature `"serde"` +impl, const CAP: usize> SerializeAs> for ArrayVec { + fn serialize_as(source: &ArrayVec, serializer: S) -> Result + where + S: Serializer, + { + serializer.collect_seq(source.iter().map(SerializeAsWrap::::new)) + } +} + +#[cfg(feature = "serde")] /// Requires crate feature `"serde"` impl<'de, T: Deserialize<'de>, const CAP: usize> Deserialize<'de> for ArrayVec { fn deserialize(deserializer: D) -> Result @@ -1286,7 +1300,7 @@ impl<'de, T: Deserialize<'de>, const CAP: usize> Deserialize<'de> for ArrayVec::new(); while let Some(value) = seq.next_element()? { - if let Err(_) = values.try_push(value) { + if values.try_push(value).is_err() { return Err(SA::Error::invalid_length(CAP + 1, &self)); } } @@ -1298,3 +1312,51 @@ impl<'de, T: Deserialize<'de>, const CAP: usize> Deserialize<'de> for ArrayVec(PhantomData)) } } + +#[cfg(feature = "serde")] +/// Requires crate feature `"serde"` +impl<'de, T, U, const CAP: usize> DeserializeAs<'de, ArrayVec> for ArrayVec +where + U: DeserializeAs<'de, T>, +{ + fn deserialize_as(deserializer: D) -> Result, D::Error> + where + D: Deserializer<'de>, + { + use serde::de::{Error, SeqAccess, Visitor}; + use std::marker::PhantomData; + + struct ArrayVecVisitor<'de, T, U, const CAP: usize>(PhantomData<(&'de (), U, [T; CAP])>); + + impl<'de, T, U, const CAP: usize> Visitor<'de> for ArrayVecVisitor<'de, T, U, CAP> + where + U: DeserializeAs<'de, T>, + { + type Value = ArrayVec; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "an array with no more than {} items", CAP) + } + + fn visit_seq(self, mut seq: SA) -> Result + where + SA: SeqAccess<'de>, + { + let mut values = ArrayVec::::new(); + + while let Some(value) = seq + .next_element()? + .map(|v: DeserializeAsWrap| v.into_inner()) + { + if let Err(_) = values.try_push(value) { + return Err(SA::Error::invalid_length(CAP + 1, &self)); + } + } + + Ok(values) + } + } + + deserializer.deserialize_seq(ArrayVecVisitor::(PhantomData)) + } +} diff --git a/tests/serde.rs b/tests/serde.rs index f02c693..cdd6f25 100644 --- a/tests/serde.rs +++ b/tests/serde.rs @@ -5,7 +5,8 @@ extern crate serde_test; mod array_vec { use arrayvec::ArrayVec; - use serde_test::{Token, assert_tokens, assert_de_tokens_error}; + use serde_test::{assert_de_tokens_error, assert_tokens, Token}; + use serde_with::{serde_as, DisplayFromStr}; #[test] fn test_ser_de_empty() { @@ -36,12 +37,44 @@ mod array_vec { #[test] fn test_de_too_large() { - assert_de_tokens_error::>(&[ - Token::Seq { len: Some(3) }, - Token::U32(13), - Token::U32(42), - Token::U32(68), - ], "invalid length 3, expected an array with no more than 2 items"); + assert_de_tokens_error::>( + &[ + Token::Seq { len: Some(3) }, + Token::U32(13), + Token::U32(42), + Token::U32(68), + ], + "invalid length 3, expected an array with no more than 2 items", + ); + } + + #[serde_as] + #[derive(serde::Serialize, serde::Deserialize, PartialEq, Eq, Debug)] + struct SerdeAs { + #[serde_as(as = "ArrayVec")] + x: ArrayVec + } + + #[test] + fn test_ser_de_as() { + let mut serde_as = SerdeAs {x: ArrayVec::::new()}; + serde_as.x.push(20); + serde_as.x.push(55); + serde_as.x.push(123); + + assert_tokens( + &serde_as, + &[ + Token::Struct { name: "SerdeAs", len: 1 }, + Token::Str("x"), + Token::Seq { len: Some(3) }, + Token::Str("20"), + Token::Str("55"), + Token::Str("123"), + Token::SeqEnd, + Token::StructEnd, + ], + ); } }