Merge pull request #679 from oli-obk/iterators

add wrapper to serde that allows serializing iterators as sequences
This commit is contained in:
David Tolnay 2017-01-12 10:19:09 -08:00 committed by GitHub
commit 110d36fa14
4 changed files with 103 additions and 1 deletions

View File

@ -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")]

View File

@ -72,6 +72,9 @@ use super::{
Serializer,
};
#[cfg(feature = "unstable")]
use super::Iterator;
///////////////////////////////////////////////////////////////////////////////
macro_rules! impl_visit {
@ -221,6 +224,33 @@ array_impls!(32);
///////////////////////////////////////////////////////////////////////////////
#[cfg(feature = "unstable")]
impl<'a, I> Serialize for Iterator<I>
where I: iter::Iterator, <I as iter::Iterator>::Item: Serialize
{
#[inline]
fn serialize<S>(&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("Iterator 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]

View File

@ -18,6 +18,13 @@ 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;
#[cfg(feature = "unstable")]
use core::iter;
pub mod impls;
///////////////////////////////////////////////////////////////////////////////
@ -410,3 +417,22 @@ 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.
#[cfg(feature = "unstable")]
pub struct Iterator<I>(RefCell<Option<I>>)
where <I as iter::Iterator>::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<I>(iter: I) -> Iterator<I>
where <I as iter::Iterator>::Item: Serialize,
I: iter::Iterator
{
Iterator(RefCell::new(Some(iter)))
}

View File

@ -15,6 +15,9 @@ use self::serde_test::{
extern crate fnv;
use self::fnv::FnvHasher;
#[cfg(feature = "unstable")]
use serde::ser::iterator;
//////////////////////////////////////////////////////////////////////////
#[derive(Serialize)]
@ -369,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() {