diff --git a/serde/src/lib.rs b/serde/src/lib.rs index 58cc9b8f..467a2266 100644 --- a/serde/src/lib.rs +++ b/serde/src/lib.rs @@ -61,7 +61,7 @@ #![doc(html_root_url="https://docs.serde.rs")] #![cfg_attr(not(feature = "std"), no_std)] -#![cfg_attr(feature = "unstable", feature(nonzero, inclusive_range, zero_one))] +#![cfg_attr(feature = "unstable", feature(inclusive_range, nonzero, specialization, zero_one))] #![cfg_attr(feature = "alloc", feature(alloc))] #![cfg_attr(feature = "collections", feature(collections))] #![cfg_attr(feature = "cargo-clippy", allow(linkedlist, type_complexity, doc_markdown))] diff --git a/serde/src/ser/impls.rs b/serde/src/ser/impls.rs index c23afdbc..f2fbb37d 100644 --- a/serde/src/ser/impls.rs +++ b/serde/src/ser/impls.rs @@ -66,9 +66,6 @@ use super::{ #[cfg(any(feature = "std", feature = "unstable"))] use super::Error; -#[cfg(feature = "unstable")] -use super::Iterator; - /////////////////////////////////////////////////////////////////////////////// macro_rules! impl_visit { @@ -147,24 +144,6 @@ impl Serialize for PhantomData { } } - -/////////////////////////////////////////////////////////////////////////////// - -impl Serialize for [T] - where T: Serialize, -{ - #[inline] - fn serialize(&self, serializer: S) -> Result - where S: Serializer, - { - let mut seq = try!(serializer.serialize_seq(Some(self.len()))); - for e in self { - try!(seq.serialize_element(e)); - } - seq.end() - } -} - /////////////////////////////////////////////////////////////////////////////// macro_rules! array_impls { @@ -220,33 +199,7 @@ array_impls!(32); /////////////////////////////////////////////////////////////////////////////// -#[cfg(feature = "unstable")] -impl<'a, I> Serialize for Iterator - where I: IntoIterator, ::Item: Serialize -{ - #[inline] - fn serialize(&self, serializer: S) -> Result - where S: Serializer, - { - // FIXME: use specialization to prevent invalidating the object in case of clonable iterators? - let iter = match self.data.borrow_mut().take() { - Some(iter) => iter.into_iter(), - None => return Err(Error::custom("Iterator used twice")), - }; - let size = match iter.size_hint() { - (lo, Some(hi)) if lo == hi => Some(lo), - _ => None, - }; - let mut seq = try!(serializer.serialize_seq(size)); - for e in iter { - try!(seq.serialize_element(&e)); - } - seq.end() - } -} - -/////////////////////////////////////////////////////////////////////////////// - +#[cfg(not(feature = "unstable"))] macro_rules! serialize_seq { () => { #[inline] @@ -262,6 +215,24 @@ macro_rules! serialize_seq { } } +#[cfg(feature = "unstable")] +macro_rules! serialize_seq { + () => { + #[inline] + fn serialize(&self, serializer: S) -> Result + where S: Serializer, + { + serializer.collect_seq(self) + } + } +} + +impl Serialize for [T] + where T: Serialize, +{ + serialize_seq!(); +} + #[cfg(any(feature = "std", feature = "collections"))] impl Serialize for BinaryHeap where T: Serialize + Ord @@ -550,6 +521,7 @@ tuple_impls! { /////////////////////////////////////////////////////////////////////////////// +#[cfg(not(feature = "unstable"))] macro_rules! serialize_map { () => { #[inline] @@ -566,6 +538,18 @@ macro_rules! serialize_map { } } +#[cfg(feature = "unstable")] +macro_rules! serialize_map { + () => { + #[inline] + fn serialize(&self, serializer: S) -> Result + where S: Serializer, + { + serializer.collect_map(self) + } + } +} + #[cfg(any(feature = "std", feature = "collections"))] impl Serialize for BTreeMap where K: Serialize + Ord, diff --git a/serde/src/ser/mod.rs b/serde/src/ser/mod.rs index 42ccd169..331928a3 100644 --- a/serde/src/ser/mod.rs +++ b/serde/src/ser/mod.rs @@ -98,10 +98,8 @@ use std::error; #[cfg(not(feature = "std"))] use error; -#[cfg(feature = "unstable")] -use core::cell::RefCell; - use core::fmt::Display; +use core::iter::IntoIterator; mod impls; mod impossible; @@ -242,7 +240,7 @@ pub trait Serialize { /// is the `serde_json::value::Serializer` (distinct from the main `serde_json` /// serializer) that produces a `serde_json::Value` data structure in memory as /// output. -pub trait Serializer { +pub trait Serializer: Sized { /// The output type produced by this `Serializer` during successful /// serialization. Most serializers that produce text or binary output /// should set `Ok = ()` and serialize into an `io::Write` or buffer @@ -607,6 +605,41 @@ pub trait Serializer { variant: &'static str, len: usize, ) -> Result; + + /// Collect an iterator as a sequence. + /// + /// The default implementation serializes each item yielded by the iterator + /// using `Self::SerializeSeq`. Implementors should not need to override + /// this method. + fn collect_seq(self, iter: I) -> Result + where I: IntoIterator, + ::Item: Serialize, + { + let iter = iter.into_iter(); + let mut serializer = try!(self.serialize_seq(iter.len_hint())); + for item in iter { + try!(serializer.serialize_element(&item)); + } + serializer.end() + } + + /// Collect an iterator as a map. + /// + /// The default implementation serializes each pair yielded by the iterator + /// using `Self::SerializeMap`. Implementors should not need to override + /// this method. + fn collect_map(self, iter: I) -> Result + where K: Serialize, + V: Serialize, + I: IntoIterator, + { + let iter = iter.into_iter(); + let mut serializer = try!(self.serialize_map(iter.len_hint())); + for (key, value) in iter { + try!(serializer.serialize_entry(&key, &value)); + } + serializer.end() + } } /// Returned from `Serializer::serialize_seq` and @@ -803,26 +836,32 @@ pub trait SerializeStructVariant { fn end(self) -> Result; } -/// A wrapper type for iterators that implements `Serialize` for iterators whose -/// items implement `Serialize`. Don't use multiple times. Create new versions -/// of this with the `serde::ser::iterator` function every time you want to -/// serialize an iterator. -#[cfg(feature = "unstable")] -pub struct Iterator - where ::Item: Serialize, - I: IntoIterator -{ - data: RefCell>, +trait LenHint: Iterator { + fn len_hint(&self) -> Option; } -/// Create a wrapper type that can be passed to any function expecting a -/// `Serialize` and will serialize the given iterator as a sequence. -#[cfg(feature = "unstable")] -pub fn iterator(iter: I) -> Iterator - where ::Item: Serialize, - I: IntoIterator -{ - Iterator { - data: RefCell::new(Some(iter)), +impl LenHint for I { + #[cfg(not(feature = "unstable"))] + fn len_hint(&self) -> Option { + iterator_len_hint(self) + } + + #[cfg(feature = "unstable")] + default fn len_hint(&self) -> Option { + iterator_len_hint(self) + } +} + +#[cfg(feature = "unstable")] +impl LenHint for I { + fn len_hint(&self) -> Option { + Some(self.len()) + } +} + +fn iterator_len_hint(iter: &I) -> Option { + match iter.size_hint() { + (lo, Some(hi)) if lo == hi => Some(lo), + _ => None, } }