From dced4416a7c150780867708b16fba7d56782a5ee Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 12 Jan 2017 15:31:40 +0100 Subject: [PATCH 1/3] add wrapper to serde that allows serializing iterators as sequences --- serde/src/lib.rs | 2 +- serde/src/ser/impls.rs | 28 ++++++++++++++++++++++++++ serde/src/ser/mod.rs | 20 +++++++++++++++++++ testing/tests/test_ser.rs | 41 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 90 insertions(+), 1 deletion(-) diff --git a/serde/src/lib.rs b/serde/src/lib.rs index 81a13620..522cf094 100644 --- a/serde/src/lib.rs +++ b/serde/src/lib.rs @@ -30,7 +30,7 @@ extern crate alloc; #[cfg(feature = "std")] mod core { pub use std::{ops, hash, fmt, cmp, marker, mem, i8, i16, i32, i64, u8, u16, u32, u64, isize, - usize, f32, f64, char, str, num, slice, iter}; + usize, f32, f64, char, str, num, slice, iter, cell}; #[cfg(feature = "unstable")] extern crate core; #[cfg(feature = "unstable")] diff --git a/serde/src/ser/impls.rs b/serde/src/ser/impls.rs index 5653a717..0705af86 100644 --- a/serde/src/ser/impls.rs +++ b/serde/src/ser/impls.rs @@ -70,6 +70,7 @@ use super::{ Error, Serialize, Serializer, + IteratorSerializer, }; /////////////////////////////////////////////////////////////////////////////// @@ -221,6 +222,33 @@ array_impls!(32); /////////////////////////////////////////////////////////////////////////////// +#[cfg(feature = "unstable")] +impl<'a, I> Serialize for IteratorSerializer + where I: Iterator, ::Item: Serialize +{ + #[inline] + fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> + where S: Serializer, + { + // FIXME: use specialization to prevent invalidating the object in case of clonable iterators? + let iter = match self.0.borrow_mut().take() { + Some(iter) => iter, + None => return Err(S::Error::custom("IteratorSerializer used twice")), + }; + let size = match iter.size_hint() { + (lo, Some(hi)) if lo == hi => Some(lo), + _ => None, + }; + let mut state = try!(serializer.serialize_seq(size)); + for e in iter { + try!(serializer.serialize_seq_elt(&mut state, e)); + } + serializer.serialize_seq_end(state) + } +} + +/////////////////////////////////////////////////////////////////////////////// + macro_rules! serialize_seq { () => { #[inline] diff --git a/serde/src/ser/mod.rs b/serde/src/ser/mod.rs index ab903b2f..ab6d08fa 100644 --- a/serde/src/ser/mod.rs +++ b/serde/src/ser/mod.rs @@ -18,6 +18,9 @@ use error; #[cfg(all(feature = "collections", not(feature = "std")))] use collections::String; +use core::marker::PhantomData; +use core::cell::RefCell; + pub mod impls; /////////////////////////////////////////////////////////////////////////////// @@ -410,3 +413,20 @@ pub trait Serializer { state: Self::StructVariantState, ) -> Result<(), Self::Error>; } + + +/// 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 `iterator` function +/// every time you want to serialize an iterator. +pub struct IteratorSerializer(RefCell>) + where ::Item: Serialize, + I: Iterator; + +/// Creates a temporary type that can be passed to any function expecting a `Serialize` and will +/// serialize the given iterator as a sequence +pub fn iterator(iter: I) -> IteratorSerializer + where ::Item: Serialize, + I: Iterator +{ + IteratorSerializer(RefCell::new(Some(iter))) +} diff --git a/testing/tests/test_ser.rs b/testing/tests/test_ser.rs index 3a5a5748..02943fab 100644 --- a/testing/tests/test_ser.rs +++ b/testing/tests/test_ser.rs @@ -15,6 +15,8 @@ use self::serde_test::{ extern crate fnv; use self::fnv::FnvHasher; +use serde::ser::iterator; + ////////////////////////////////////////////////////////////////////////// #[derive(Serialize)] @@ -98,6 +100,45 @@ declare_ser_tests! { Token::I32(1), ], } + test_iterator { + iterator([0; 0].iter()) => &[ + Token::SeqStart(Some(0)), + Token::SeqEnd, + ], + iterator([1, 2, 3].iter()) => &[ + Token::SeqStart(Some(3)), + Token::SeqSep, + Token::I32(1), + + Token::SeqSep, + Token::I32(2), + + Token::SeqSep, + Token::I32(3), + Token::SeqEnd, + ], + iterator([1, 2, 3].iter().map(|x| x * 2)) => &[ + Token::SeqStart(Some(3)), + Token::SeqSep, + Token::I32(2), + + Token::SeqSep, + Token::I32(4), + + Token::SeqSep, + Token::I32(6), + Token::SeqEnd, + ], + iterator([1, 2, 3].iter().filter(|&x| x % 2 != 0)) => &[ + Token::SeqStart(None), + Token::SeqSep, + Token::I32(1), + + Token::SeqSep, + Token::I32(3), + Token::SeqEnd, + ], + } test_slice { &[0][..0] => &[ Token::SeqStart(Some(0)), From b860d3cb1f7b09404894f19e40fa6b87b45f7dbe Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 12 Jan 2017 16:06:26 +0100 Subject: [PATCH 2/3] fix tests on stable --- serde/src/ser/impls.rs | 4 +- serde/src/ser/mod.rs | 4 ++ testing/tests/test_ser.rs | 83 +++++++++++++++++++++------------------ 3 files changed, 51 insertions(+), 40 deletions(-) diff --git a/serde/src/ser/impls.rs b/serde/src/ser/impls.rs index 0705af86..51981869 100644 --- a/serde/src/ser/impls.rs +++ b/serde/src/ser/impls.rs @@ -70,9 +70,11 @@ use super::{ Error, Serialize, Serializer, - IteratorSerializer, }; +#[cfg(feature = "unstable")] +use super::IteratorSerializer; + /////////////////////////////////////////////////////////////////////////////// macro_rules! impl_visit { diff --git a/serde/src/ser/mod.rs b/serde/src/ser/mod.rs index ab6d08fa..97784ef0 100644 --- a/serde/src/ser/mod.rs +++ b/serde/src/ser/mod.rs @@ -18,7 +18,9 @@ use error; #[cfg(all(feature = "collections", not(feature = "std")))] use collections::String; +#[cfg(feature = "unstable")] use core::marker::PhantomData; +#[cfg(feature = "unstable")] use core::cell::RefCell; pub mod impls; @@ -418,12 +420,14 @@ pub trait Serializer { /// 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 `iterator` function /// every time you want to serialize an iterator. +#[cfg(feature = "unstable")] pub struct IteratorSerializer(RefCell>) where ::Item: Serialize, I: Iterator; /// Creates a temporary 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) -> IteratorSerializer where ::Item: Serialize, I: Iterator diff --git a/testing/tests/test_ser.rs b/testing/tests/test_ser.rs index 02943fab..5d54b432 100644 --- a/testing/tests/test_ser.rs +++ b/testing/tests/test_ser.rs @@ -15,6 +15,7 @@ use self::serde_test::{ extern crate fnv; use self::fnv::FnvHasher; +#[cfg(feature = "unstable")] use serde::ser::iterator; ////////////////////////////////////////////////////////////////////////// @@ -100,45 +101,6 @@ declare_ser_tests! { Token::I32(1), ], } - test_iterator { - iterator([0; 0].iter()) => &[ - Token::SeqStart(Some(0)), - Token::SeqEnd, - ], - iterator([1, 2, 3].iter()) => &[ - Token::SeqStart(Some(3)), - Token::SeqSep, - Token::I32(1), - - Token::SeqSep, - Token::I32(2), - - Token::SeqSep, - Token::I32(3), - Token::SeqEnd, - ], - iterator([1, 2, 3].iter().map(|x| x * 2)) => &[ - Token::SeqStart(Some(3)), - Token::SeqSep, - Token::I32(2), - - Token::SeqSep, - Token::I32(4), - - Token::SeqSep, - Token::I32(6), - Token::SeqEnd, - ], - iterator([1, 2, 3].iter().filter(|&x| x % 2 != 0)) => &[ - Token::SeqStart(None), - Token::SeqSep, - Token::I32(1), - - Token::SeqSep, - Token::I32(3), - Token::SeqEnd, - ], - } test_slice { &[0][..0] => &[ Token::SeqStart(Some(0)), @@ -410,6 +372,49 @@ declare_ser_tests! { } } + +#[cfg(feature = "unstable")] +#[test] +fn test_iterator() { + assert_ser_tokens(iterator([0; 0].iter()), &[ + Token::SeqStart(Some(0)), + Token::SeqEnd, + ]); + assert_ser_tokens(iterator([1, 2, 3].iter()), &[ + Token::SeqStart(Some(3)), + Token::SeqSep, + Token::I32(1), + + Token::SeqSep, + Token::I32(2), + + Token::SeqSep, + Token::I32(3), + Token::SeqEnd, + ]); + assert_ser_tokens(iterator([1, 2, 3].iter().map(|x| x * 2)), &[ + Token::SeqStart(Some(3)), + Token::SeqSep, + Token::I32(2), + + Token::SeqSep, + Token::I32(4), + + Token::SeqSep, + Token::I32(6), + Token::SeqEnd, + ]); + assert_ser_tokens(iterator([1, 2, 3].iter().filter(|&x| x % 2 != 0)), &[ + Token::SeqStart(None), + Token::SeqSep, + Token::I32(1), + + Token::SeqSep, + Token::I32(3), + Token::SeqEnd, + ]); +} + #[cfg(feature = "unstable")] #[test] fn test_net_ipaddr() { From 8c576fe9fb3749a2b4218fc577902fdf59238cb9 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 12 Jan 2017 17:29:04 +0100 Subject: [PATCH 3/3] rename IteratorSerializer to Iterator --- serde/src/ser/impls.rs | 8 ++++---- serde/src/ser/mod.rs | 16 +++++++++------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/serde/src/ser/impls.rs b/serde/src/ser/impls.rs index 51981869..17cd872b 100644 --- a/serde/src/ser/impls.rs +++ b/serde/src/ser/impls.rs @@ -73,7 +73,7 @@ use super::{ }; #[cfg(feature = "unstable")] -use super::IteratorSerializer; +use super::Iterator; /////////////////////////////////////////////////////////////////////////////// @@ -225,8 +225,8 @@ array_impls!(32); /////////////////////////////////////////////////////////////////////////////// #[cfg(feature = "unstable")] -impl<'a, I> Serialize for IteratorSerializer - where I: Iterator, ::Item: Serialize +impl<'a, I> Serialize for Iterator + where I: iter::Iterator, ::Item: Serialize { #[inline] fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> @@ -235,7 +235,7 @@ impl<'a, I> Serialize for IteratorSerializer // FIXME: use specialization to prevent invalidating the object in case of clonable iterators? let iter = match self.0.borrow_mut().take() { Some(iter) => iter, - None => return Err(S::Error::custom("IteratorSerializer used twice")), + None => return Err(S::Error::custom("Iterator used twice")), }; let size = match iter.size_hint() { (lo, Some(hi)) if lo == hi => Some(lo), diff --git a/serde/src/ser/mod.rs b/serde/src/ser/mod.rs index 97784ef0..942ad984 100644 --- a/serde/src/ser/mod.rs +++ b/serde/src/ser/mod.rs @@ -22,6 +22,8 @@ use collections::String; use core::marker::PhantomData; #[cfg(feature = "unstable")] use core::cell::RefCell; +#[cfg(feature = "unstable")] +use core::iter; pub mod impls; @@ -421,16 +423,16 @@ pub trait Serializer { /// `Serialize`. Don't use multiple times. Create new versions of this with the `iterator` function /// every time you want to serialize an iterator. #[cfg(feature = "unstable")] -pub struct IteratorSerializer(RefCell>) - where ::Item: Serialize, - I: Iterator; +pub struct Iterator(RefCell>) + where ::Item: Serialize, + I: iter::Iterator; /// Creates a temporary 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) -> IteratorSerializer - where ::Item: Serialize, - I: Iterator +pub fn iterator(iter: I) -> Iterator + where ::Item: Serialize, + I: iter::Iterator { - IteratorSerializer(RefCell::new(Some(iter))) + Iterator(RefCell::new(Some(iter))) }