[−][src]Module serde_iter::seq
Serializes an iterator of serializables into a serde sequence.
This module requires the "seq" feature to be enabled (enabled by default).
Usage
To derive Serialize
for a struct that contains arbitrary Iterator
types,
simply add #[serde(with = "serde_iter::seq")]
on the fields using such types.
Example
#[derive(serde::Serialize)] struct Foo { #[serde(with = "serde_iter::seq")] bar: std::iter::Once<i32>, } let foo = Foo { bar: std::iter::once(2), }; assert_eq!(serde_json::to_value(&foo).unwrap(), serde_json::json!({ "bar": [2] }));
Cloning
Since serialization could be called multiple times on the same value,
each time the iterator is serialized, serde_iter
would clone the iterator and only consume
the clone.
As a result, the Iterator type must implement Clone
, which is not implemented by all
Iterator
types.
For example, std::vec::Drain
does not implement Clone
, because consuming the iterator
modifies the Vec
, and doing so multiple times would lead to different semantics:
#[derive(serde::Serialize)] struct Foo<'a> { #[serde(with = "serde_iter::seq")] bar: std::vec::Drain<'a, i32>, } let mut v = vec![]; serde_json::to_value(&Foo { bar: v.drain(..) }).unwrap();;
This fails to compile, because if the serde_json::to_value
is called twice, unexpected
behaviour would occur: should it yield inconsistent results, or otherwise store the drained
data somewhere else?
Furthermore, since cloning is not cost-free, if cloning the iterator involves cloning the
iterated object, it is advised that the iterated type be a Copy
,
or at least some low-cost Clone
(and low-cost Drop
).
For example, Rc::clone()
/Rc::drop()
only increments/decrements a refcount value, so it is
relatively cheap.
On the other hand, String::clone()
allocates a new buffer on the heap and copies all
characters to the new buffer, which is not low-cost, and it is better to borrow the strings.
Consider this example:
static counter: AtomicU8 = AtomicU8::new(0); fn do_something_costly() { counter.fetch_add(1, Ordering::Relaxed); } #[derive(serde::Serialize)] struct Costly; impl Clone for Costly { fn clone(&self) -> Self { do_something_costly(); Self } } #[derive(serde::Serialize)] struct Foo<T: Iterator<Item = V> + Clone, V: Serialize> { #[serde(with = "serde_iter::seq")] bar: T, } let v = vec![Costly]; // we just have one Costly item let foo = Foo { bar: v.into_iter() }; assert_eq!(counter.load(Ordering::Relaxed), 0); serde_json::to_string(&foo).unwrap(); assert_eq!(counter.load(Ordering::Relaxed), 1); serde_json::to_string(&foo).unwrap(); assert_eq!(counter.load(Ordering::Relaxed), 2);
The Costly
type gets cloned once on every serialization.
This is because each serialization clones Costly
.
This may result in significant differences for non-Copy
types,
such as String
.
On the other hand, if the iterator only contains references ot the cloned type:
// Previous definitions unchanged let v = vec![Costly]; // we just have one Costly item let foo = Foo { bar: v.iter() }; assert_eq!(counter.load(Ordering::Relaxed), 0); serde_json::to_string(&foo).unwrap(); assert_eq!(counter.load(Ordering::Relaxed), 0); serde_json::to_string(&foo).unwrap(); assert_eq!(counter.load(Ordering::Relaxed), 0);
Since v.iter()
only iterates &Costly
but not Costly
, no clones are performed.
Note that this this distinction mainly applies for pre-existing values.
If the clonable value is created during iteration,
e.g. if it is iter.map(|x| x.to_string())
,
borrowing would not improve anything;
to prevent cloning unnecessarily, it might be desirable to
store the mapped data in a Vec
beforehand.
Functions
serialize | Refer to the module-level documentation. |