From bc221abb04ed942afed87a41147802f1c7d3955a Mon Sep 17 00:00:00 2001 From: Alexis Beingessner Date: Mon, 13 Nov 2017 13:38:27 -0500 Subject: [PATCH] Augment builtin std/core Deserialize impls to implement deserialize_from --- serde/src/de/impls.rs | 338 +++++++++++++++++++++++++++++++++------- serde/src/private/de.rs | 19 ++- 2 files changed, 304 insertions(+), 53 deletions(-) diff --git a/serde/src/de/impls.rs b/serde/src/de/impls.rs index ea48d34e..c7ea2ede 100644 --- a/serde/src/de/impls.rs +++ b/serde/src/de/impls.rs @@ -15,6 +15,7 @@ use de::{Deserialize, Deserializer, EnumAccess, Error, SeqAccess, Unexpected, Va use de::MapAccess; use de::from_primitive::FromPrimitive; +use private::de::DeserializeFromSeed; #[cfg(any(feature = "std", feature = "alloc"))] use private::de::size_hint; @@ -51,6 +52,7 @@ impl<'de> Deserialize<'de> for () { struct BoolVisitor; + impl<'de> Visitor<'de> for BoolVisitor { type Value = bool; @@ -210,6 +212,8 @@ impl<'de> Deserialize<'de> for char { #[cfg(any(feature = "std", feature = "alloc"))] struct StringVisitor; +#[cfg(any(feature = "std", feature = "alloc"))] +struct StringFromVisitor<'a>(&'a mut String); #[cfg(any(feature = "std", feature = "alloc"))] impl<'de> Visitor<'de> for StringVisitor { @@ -254,6 +258,59 @@ impl<'de> Visitor<'de> for StringVisitor { } } +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'a, 'de> Visitor<'de> for StringFromVisitor<'a> { + type Value = (); + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a string") + } + + fn visit_str(self, v: &str) -> Result<(), E> + where + E: Error, + { + self.0.clear(); + self.0.push_str(v); + Ok(()) + } + + fn visit_string(self, v: String) -> Result<(), E> + where + E: Error, + { + *self.0 = v; + Ok(()) + } + + fn visit_bytes(self, v: &[u8]) -> Result<(), E> + where + E: Error, + { + match str::from_utf8(v) { + Ok(s) => { + self.0.clear(); + self.0.push_str(s); + Ok(()) + } + Err(_) => Err(Error::invalid_value(Unexpected::Bytes(v), &self)), + } + } + + fn visit_byte_buf(self, v: Vec) -> Result<(), E> + where + E: Error, + { + match String::from_utf8(v) { + Ok(s) => { + *self.0 = s; + Ok(()) + } + Err(e) => Err(Error::invalid_value(Unexpected::Bytes(&e.into_bytes()), &self),), + } + } +} + #[cfg(any(feature = "std", feature = "alloc"))] impl<'de> Deserialize<'de> for String { fn deserialize(deserializer: D) -> Result @@ -262,6 +319,13 @@ impl<'de> Deserialize<'de> for String { { deserializer.deserialize_string(StringVisitor) } + + fn deserialize_from(&mut self, deserializer: D) -> Result<(), D::Error> + where + D: Deserializer<'de>, + { + deserializer.deserialize_string(StringFromVisitor(self)) + } } //////////////////////////////////////////////////////////////////////////////// @@ -421,6 +485,7 @@ forwarded_impl!((), Box, CString::into_boxed_c_str); struct OptionVisitor { marker: PhantomData, } +struct OptionFromVisitor<'a, T: 'a>(&'a mut Option); impl<'de, T> Visitor<'de> for OptionVisitor where @@ -457,6 +522,49 @@ where } } +impl<'a, 'de, T> Visitor<'de> for OptionFromVisitor<'a, T> +where + T: Deserialize<'de>, +{ + type Value = (); + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("option") + } + + #[inline] + fn visit_unit(self) -> Result<(), E> + where + E: Error, + { + *self.0 = None; + Ok(()) + } + + #[inline] + fn visit_none(self) -> Result<(), E> + where + E: Error, + { + *self.0 = None; + Ok(()) + } + + #[inline] + fn visit_some(self, deserializer: D) -> Result<(), D::Error> + where + D: Deserializer<'de>, + { + // The some enum's repr is opaque, so we can't play cute tricks with + // its tag to build this in place unconditionally. + // + // FIXME: investigate whether branching on the old value being Some to + // deserialize_from the value is profitable (probably data-dependent?) + *self.0 = try!(T::deserialize(deserializer).map(Some)); + Ok(()) + } +} + impl<'de, T> Deserialize<'de> for Option where T: Deserialize<'de>, @@ -467,6 +575,13 @@ where { deserializer.deserialize_option(OptionVisitor { marker: PhantomData }) } + + fn deserialize_from(&mut self, deserializer: D) -> Result<(), D::Error> + where + D: Deserializer<'de>, + { + deserializer.deserialize_option(OptionFromVisitor(self)) + } } //////////////////////////////////////////////////////////////////////////////// @@ -509,7 +624,9 @@ macro_rules! seq_impl { $ty:ident < T $(: $tbound1:ident $(+ $tbound2:ident)*)* $(, $typaram:ident : $bound1:ident $(+ $bound2:ident)*)* >, $access:ident, $ctor:expr, + $clear:expr, $with_capacity:expr, + $reserve:expr, $insert:expr ) => { impl<'de, T $(, $typaram)*> Deserialize<'de> for $ty @@ -554,16 +671,59 @@ macro_rules! seq_impl { let visitor = SeqVisitor { marker: PhantomData }; deserializer.deserialize_seq(visitor) } + + fn deserialize_from(&mut self, deserializer: D) -> Result<(), D::Error> + where + D: Deserializer<'de>, + { + struct SeqVisitor<'a, T: 'a $(, $typaram: 'a)*>(&'a mut $ty); + + impl<'a, 'de, T $(, $typaram)*> Visitor<'de> for SeqVisitor<'a, T $(, $typaram)*> + where + T: Deserialize<'de> $(+ $tbound1 $(+ $tbound2)*)*, + $($typaram: $bound1 $(+ $bound2)*,)* + { + type Value = (); + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a sequence") + } + + #[inline] + fn visit_seq(mut self, mut $access: A) -> Result<(), A::Error> + where + A: SeqAccess<'de>, + { + $clear(&mut self.0); + $reserve(&mut self.0, size_hint::cautious($access.size_hint())); + + // FIXME: try to overwrite old values here? (Vec, VecDeque, LinkedList) + while let Some(value) = try!($access.next_element()) { + $insert(&mut self.0, value); + } + + Ok(()) + } + } + + deserializer.deserialize_seq(SeqVisitor(self)) + } } } } +// Dummy impl of reserve +#[cfg(any(feature = "std", feature = "alloc"))] +fn nop_reserve(_x: T, _y: U) { } + #[cfg(any(feature = "std", feature = "alloc"))] seq_impl!( BinaryHeap, seq, BinaryHeap::new(), + BinaryHeap::clear, BinaryHeap::with_capacity(size_hint::cautious(seq.size_hint())), + BinaryHeap::reserve, BinaryHeap::push); #[cfg(any(feature = "std", feature = "alloc"))] @@ -571,7 +731,9 @@ seq_impl!( BTreeSet, seq, BTreeSet::new(), + BTreeSet::clear, BTreeSet::new(), + nop_reserve, BTreeSet::insert); #[cfg(any(feature = "std", feature = "alloc"))] @@ -579,7 +741,9 @@ seq_impl!( LinkedList, seq, LinkedList::new(), + LinkedList::clear, LinkedList::new(), + nop_reserve, LinkedList::push_back); #[cfg(feature = "std")] @@ -587,7 +751,9 @@ seq_impl!( HashSet, seq, HashSet::with_hasher(S::default()), + HashSet::clear, HashSet::with_capacity_and_hasher(size_hint::cautious(seq.size_hint()), S::default()), + HashSet::reserve, HashSet::insert); #[cfg(any(feature = "std", feature = "alloc"))] @@ -595,7 +761,9 @@ seq_impl!( Vec, seq, Vec::new(), + Vec::clear, Vec::with_capacity(size_hint::cautious(seq.size_hint())), + Vec::reserve, Vec::push); #[cfg(any(feature = "std", feature = "alloc"))] @@ -603,7 +771,9 @@ seq_impl!( VecDeque, seq, VecDeque::new(), + VecDeque::clear, VecDeque::with_capacity(size_hint::cautious(seq.size_hint())), + VecDeque::reserve, VecDeque::push_back); //////////////////////////////////////////////////////////////////////////////// @@ -611,6 +781,7 @@ seq_impl!( struct ArrayVisitor { marker: PhantomData, } +struct ArrayFromVisitor<'a, A: 'a>(&'a mut A); impl ArrayVisitor { fn new() -> Self { @@ -673,6 +844,35 @@ macro_rules! array_impls { } } + impl<'a, 'de, T> Visitor<'de> for ArrayFromVisitor<'a, [T; $len]> + where + T: Deserialize<'de>, + { + type Value = (); + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str(concat!("an array of length ", $len)) + } + + #[inline] + fn visit_seq(self, mut seq: A) -> Result<(), A::Error> + where + A: SeqAccess<'de>, + { + let mut fail_idx = None; + for (idx, dest) in self.0[..].iter_mut().enumerate() { + if try!(seq.next_element_seed(DeserializeFromSeed(dest))).is_none() { + fail_idx = Some(idx); + break; + } + } + if let Some(idx) = fail_idx { + return Err(Error::invalid_length(idx, &self)); + } + Ok(()) + } + } + impl<'de, T> Deserialize<'de> for [T; $len] where T: Deserialize<'de>, @@ -683,6 +883,13 @@ macro_rules! array_impls { { deserializer.deserialize_tuple($len, ArrayVisitor::<[T; $len]>::new()) } + + fn deserialize_from(&mut self, deserializer: D) -> Result<(), D::Error> + where + D: Deserializer<'de>, + { + deserializer.deserialize_tuple($len, ArrayFromVisitor(self)) + } } )+ } @@ -726,49 +933,76 @@ array_impls! { //////////////////////////////////////////////////////////////////////////////// macro_rules! tuple_impls { - ($($len:tt $visitor:ident => ($($n:tt $name:ident)+))+) => { + ($($len:tt => ($($n:tt $name:ident)+))+) => { $( - struct $visitor<$($name,)+> { - marker: PhantomData<($($name,)+)>, - } - - impl<$($name,)+> $visitor<$($name,)+> { - fn new() -> Self { - $visitor { marker: PhantomData } - } - } - - impl<'de, $($name: Deserialize<'de>),+> Visitor<'de> for $visitor<$($name,)+> { - type Value = ($($name,)+); - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str(concat!("a tuple of size ", $len)) - } - - #[inline] - #[allow(non_snake_case)] - fn visit_seq(self, mut seq: A) -> Result<($($name,)+), A::Error> - where - A: SeqAccess<'de>, - { - $( - let $name = match try!(seq.next_element()) { - Some(value) => value, - None => return Err(Error::invalid_length($n, &self)), - }; - )+ - - Ok(($($name,)+)) - } - } - impl<'de, $($name: Deserialize<'de>),+> Deserialize<'de> for ($($name,)+) { #[inline] fn deserialize(deserializer: D) -> Result<($($name,)+), D::Error> where D: Deserializer<'de>, { - deserializer.deserialize_tuple($len, $visitor::new()) + struct TupleVisitor<$($name,)+> { + marker: PhantomData<($($name,)+)>, + } + + impl<'de, $($name: Deserialize<'de>),+> Visitor<'de> for TupleVisitor<$($name,)+> { + type Value = ($($name,)+); + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str(concat!("a tuple of size ", $len)) + } + + #[inline] + #[allow(non_snake_case)] + fn visit_seq(self, mut seq: A) -> Result<($($name,)+), A::Error> + where + A: SeqAccess<'de>, + { + $( + let $name = match try!(seq.next_element()) { + Some(value) => value, + None => return Err(Error::invalid_length($n, &self)), + }; + )+ + + Ok(($($name,)+)) + } + } + + deserializer.deserialize_tuple($len, TupleVisitor { marker: PhantomData }) + } + + #[inline] + fn deserialize_from(&mut self, deserializer: D) -> Result<(), D::Error> + where + D: Deserializer<'de>, + { + struct TupleVisitor<'a, $($name: 'a,)+>(&'a mut ($($name,)+)); + + impl<'a, 'de, $($name: Deserialize<'de>),+> Visitor<'de> for TupleVisitor<'a, $($name,)+> { + type Value = (); + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str(concat!("a tuple of size ", $len)) + } + + #[inline] + #[allow(non_snake_case)] + fn visit_seq(self, mut seq: A) -> Result<(), A::Error> + where + A: SeqAccess<'de>, + { + $( + if try!(seq.next_element_seed(DeserializeFromSeed(&mut (self.0).$n))).is_none() { + return Err(Error::invalid_length($n, &self)); + } + )+ + + Ok(()) + } + } + + deserializer.deserialize_tuple($len, TupleVisitor(self)) } } )+ @@ -776,22 +1010,22 @@ macro_rules! tuple_impls { } tuple_impls! { - 1 TupleVisitor1 => (0 T0) - 2 TupleVisitor2 => (0 T0 1 T1) - 3 TupleVisitor3 => (0 T0 1 T1 2 T2) - 4 TupleVisitor4 => (0 T0 1 T1 2 T2 3 T3) - 5 TupleVisitor5 => (0 T0 1 T1 2 T2 3 T3 4 T4) - 6 TupleVisitor6 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5) - 7 TupleVisitor7 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6) - 8 TupleVisitor8 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7) - 9 TupleVisitor9 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8) - 10 TupleVisitor10 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9) - 11 TupleVisitor11 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10) - 12 TupleVisitor12 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11) - 13 TupleVisitor13 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12) - 14 TupleVisitor14 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13) - 15 TupleVisitor15 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14) - 16 TupleVisitor16 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14 15 T15) + 1 => (0 T0) + 2 => (0 T0 1 T1) + 3 => (0 T0 1 T1 2 T2) + 4 => (0 T0 1 T1 2 T2 3 T3) + 5 => (0 T0 1 T1 2 T2 3 T3 4 T4) + 6 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5) + 7 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6) + 8 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7) + 9 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8) + 10 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9) + 11 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10) + 12 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11) + 13 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12) + 14 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13) + 15 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14) + 16 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14 15 T15) } //////////////////////////////////////////////////////////////////////////////// diff --git a/serde/src/private/de.rs b/serde/src/private/de.rs index 7c98d9f9..a3134e69 100644 --- a/serde/src/private/de.rs +++ b/serde/src/private/de.rs @@ -8,7 +8,7 @@ use lib::*; -use de::{Deserialize, Deserializer, IntoDeserializer, Error, Visitor}; +use de::{Deserialize, Deserializer, DeserializeSeed, IntoDeserializer, Error, Visitor}; #[cfg(any(feature = "std", feature = "alloc"))] use de::Unexpected; @@ -2009,3 +2009,20 @@ where map struct enum identifier ignored_any } } + +/// A DeserializeSeed helper for implementing deserialize_from Visitors. +/// +/// Wraps a mutable reference and calls deserialize_from on it. +pub struct DeserializeFromSeed<'a, T: 'a>(pub &'a mut T); + +impl<'a, 'de, T> DeserializeSeed<'de> for DeserializeFromSeed<'a, T> + where T: Deserialize<'de>, +{ + type Value = (); + fn deserialize(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + self.0.deserialize_from(deserializer) + } +}