From d00a8959026c9eef18b90b8b373486027b1e351f Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Tue, 31 Jan 2017 22:59:09 +0100 Subject: [PATCH 1/5] Introduce Serializer::collect_seq This function serializes the given iterator as a sequence. Its iter parameter has type I: IntoIterator, ::Item: Serialize, which means it will work both for iterators passed by value, therefore consuming them, and as the value for a #[serde(serialize_with)] attribute, where it will be called as Serializer::collect_seq(&self.field, serializer), relying on the common practice of implementing IntoIterator for &C where C is a data type representing some kind of collection. --- serde/src/ser/mod.rs | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/serde/src/ser/mod.rs b/serde/src/ser/mod.rs index 42ccd169..9fa5ca32 100644 --- a/serde/src/ser/mod.rs +++ b/serde/src/ser/mod.rs @@ -102,6 +102,7 @@ use error; use core::cell::RefCell; use core::fmt::Display; +use core::iter::IntoIterator; mod impls; mod impossible; @@ -242,7 +243,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 +608,23 @@ 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(iterator_len_hint(&iter))); + for item in iter { + try!(serializer.serialize_element(&item)); + } + serializer.end() + } } /// Returned from `Serializer::serialize_seq` and @@ -826,3 +844,10 @@ pub fn iterator(iter: I) -> Iterator data: RefCell::new(Some(iter)), } } + +fn iterator_len_hint(iter: &I) -> Option { + match iter.size_hint() { + (lo, Some(hi)) if lo == hi => Some(lo), + _ => None, + } +} From 89bb16da6bc0be3290bf4ebe80db5ea46c27dbc1 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Fri, 3 Feb 2017 21:09:54 +0100 Subject: [PATCH 2/5] Introduce Serializer::collect_map --- serde/src/ser/mod.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/serde/src/ser/mod.rs b/serde/src/ser/mod.rs index 9fa5ca32..a1528839 100644 --- a/serde/src/ser/mod.rs +++ b/serde/src/ser/mod.rs @@ -625,6 +625,24 @@ pub trait Serializer: Sized { } 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(iterator_len_hint(&iter))); + for (key, value) in iter { + try!(serializer.serialize_entry(&key, &value)); + } + serializer.end() + } } /// Returned from `Serializer::serialize_seq` and From 30b8036efafe4820fb11b718c1fb013e01f0039b Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sat, 4 Feb 2017 11:52:48 +0100 Subject: [PATCH 3/5] Remove ser::Iterator --- serde/src/ser/impls.rs | 30 ------------------------------ serde/src/ser/mod.rs | 27 --------------------------- 2 files changed, 57 deletions(-) diff --git a/serde/src/ser/impls.rs b/serde/src/ser/impls.rs index c23afdbc..61f2c1fd 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 { @@ -220,33 +217,6 @@ 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() - } -} - -/////////////////////////////////////////////////////////////////////////////// - macro_rules! serialize_seq { () => { #[inline] diff --git a/serde/src/ser/mod.rs b/serde/src/ser/mod.rs index a1528839..c7635c34 100644 --- a/serde/src/ser/mod.rs +++ b/serde/src/ser/mod.rs @@ -98,9 +98,6 @@ use std::error; #[cfg(not(feature = "std"))] use error; -#[cfg(feature = "unstable")] -use core::cell::RefCell; - use core::fmt::Display; use core::iter::IntoIterator; @@ -839,30 +836,6 @@ 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>, -} - -/// 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)), - } -} - fn iterator_len_hint(iter: &I) -> Option { match iter.size_hint() { (lo, Some(hi)) if lo == hi => Some(lo), From 763ab9c2a1cd2b033b2dd6399812f65af8bfe44c Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sat, 4 Feb 2017 12:21:45 +0100 Subject: [PATCH 4/5] Use serialize_seq! to implement Serialize for [T] --- serde/src/ser/impls.rs | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/serde/src/ser/impls.rs b/serde/src/ser/impls.rs index 61f2c1fd..93c00dc4 100644 --- a/serde/src/ser/impls.rs +++ b/serde/src/ser/impls.rs @@ -144,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 { @@ -232,6 +214,12 @@ macro_rules! serialize_seq { } } +impl Serialize for [T] + where T: Serialize, +{ + serialize_seq!(); +} + #[cfg(any(feature = "std", feature = "collections"))] impl Serialize for BinaryHeap where T: Serialize + Ord From 17c175a1a6bde98e947b1b02872a138c6afdb1fc Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sat, 4 Feb 2017 12:22:58 +0100 Subject: [PATCH 5/5] Use specialisation to optimise collect_seq and collect_map --- serde/src/lib.rs | 2 +- serde/src/ser/impls.rs | 26 ++++++++++++++++++++++++++ serde/src/ser/mod.rs | 27 +++++++++++++++++++++++++-- 3 files changed, 52 insertions(+), 3 deletions(-) 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 93c00dc4..f2fbb37d 100644 --- a/serde/src/ser/impls.rs +++ b/serde/src/ser/impls.rs @@ -199,6 +199,7 @@ array_impls!(32); /////////////////////////////////////////////////////////////////////////////// +#[cfg(not(feature = "unstable"))] macro_rules! serialize_seq { () => { #[inline] @@ -214,6 +215,18 @@ 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, { @@ -508,6 +521,7 @@ tuple_impls! { /////////////////////////////////////////////////////////////////////////////// +#[cfg(not(feature = "unstable"))] macro_rules! serialize_map { () => { #[inline] @@ -524,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 c7635c34..331928a3 100644 --- a/serde/src/ser/mod.rs +++ b/serde/src/ser/mod.rs @@ -616,7 +616,7 @@ pub trait Serializer: Sized { ::Item: Serialize, { let iter = iter.into_iter(); - let mut serializer = try!(self.serialize_seq(iterator_len_hint(&iter))); + let mut serializer = try!(self.serialize_seq(iter.len_hint())); for item in iter { try!(serializer.serialize_element(&item)); } @@ -634,7 +634,7 @@ pub trait Serializer: Sized { I: IntoIterator, { let iter = iter.into_iter(); - let mut serializer = try!(self.serialize_map(iterator_len_hint(&iter))); + let mut serializer = try!(self.serialize_map(iter.len_hint())); for (key, value) in iter { try!(serializer.serialize_entry(&key, &value)); } @@ -836,6 +836,29 @@ pub trait SerializeStructVariant { fn end(self) -> Result; } +trait LenHint: Iterator { + fn len_hint(&self) -> Option; +} + +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),