pub struct SinkHandle<'a, 'de: 'a>(/* private fields */);Expand description
A handle to a Sink.
During deserialization the sinks often need to return other sinks
to recurse into structures. This poses a challenge if the target
sink cannot be directly borrowed. This is where SinkHandle
comes in. In cases where the Sink cannot be borrowed it’s owned
by the handle, either in the arena of the state
(arena, which is what sinks typically use) or on the
heap (heap).
The handle itself implements Sink and forwards all calls to the
sink it holds.
Unlike the SerializeHandle of
serialization, which holds a value that is not serialized yet, this
holds a sink that is already deserializing a value. The serialization
equivalent of a sink is an emitter in a Emit.
The constructors line up: to borrows,
arena and heap own in the same way for
both handles.
Implementations§
Source§impl<'a, 'de> SinkHandle<'a, 'de>
impl<'a, 'de> SinkHandle<'a, 'de>
Sourcepub fn to(sink: &'a mut dyn Sink<'de>) -> SinkHandle<'a, 'de>
pub fn to(sink: &'a mut dyn Sink<'de>) -> SinkHandle<'a, 'de>
Create a borrowed handle to a Sink.
Sourcepub fn arena<S: Sink<'de> + 'a>(
sink: S,
state: &mut State,
) -> SinkHandle<'a, 'de>
pub fn arena<S: Sink<'de> + 'a>( sink: S, state: &mut State, ) -> SinkHandle<'a, 'de>
Creates an owned handle to a sink in the arena of the state.
This is how sinks are typically created: the arena belongs to the state of the deserialization and the sinks of the containers that are open are on top of each other in it, allocating one is little more than bumping a pointer. Its space is reused once the handle is dropped (and the sinks allocated after it are dropped too).
A sink can outlive the deserialization it was created for (the
state). The arena then frees its memory except for the chunk the
sink is in, which is freed when the sink is dropped (and the other
sinks in it). A sink that is meant to be kept for longer should
rather be created with heap.
use deser::de::{Deserialize, DeserializeDriver, Sink, SinkHandle};
use deser::{Error, Event, State};
/// The number of items of a sequence.
struct Count(usize);
struct CountSink<'a> {
out: &'a mut Option<Count>,
count: usize,
}
impl<'de> Sink<'de> for CountSink<'_> {
fn seq(&mut self, _state: &mut State) -> Result<(), Error> {
Ok(())
}
fn next_value(
&mut self,
_state: &mut State,
) -> Result<SinkHandle<'_, 'de>, Error> {
self.count += 1;
// the items themselves are ignored
Ok(SinkHandle::null())
}
fn finish(&mut self, _state: &mut State) -> Result<(), Error> {
*self.out = Some(Count(self.count));
Ok(())
}
}
impl<'de> Deserialize<'de> for Count {
fn deserialize_into<'a>(
out: &'a mut Option<Self>,
state: &mut State,
) -> SinkHandle<'a, 'de> {
SinkHandle::arena(CountSink { out, count: 0 }, state)
}
}
let mut out = None::<Count>;
let mut driver = DeserializeDriver::new(&mut out);
for event in [Event::seq_start(), "a".into(), "b".into(), Event::SeqEnd] {
driver.emit(event).unwrap();
}
drop(driver);
assert_eq!(out.unwrap().0, 2);Sourcepub fn heap<S: Sink<'de> + 'a>(sink: S) -> SinkHandle<'a, 'de>
pub fn heap<S: Sink<'de> + 'a>(sink: S) -> SinkHandle<'a, 'de>
Creates an owned handle to a sink on the heap.
Unlike arena the sink does not need a state and is
independent of any deserialization, but every sink is a separate
allocation.
Sourcepub fn null() -> SinkHandle<'a, 'de>
pub fn null() -> SinkHandle<'a, 'de>
Creates a sink handle that drops all values.
This can be used in places where a sink is required but no value wants to be collected. For instance it can be tricky to provide a mutable reference to a sink from a function that doesn’t have a way to put a slot somewhere.
Sourcepub fn shorten<'b>(self) -> SinkHandle<'b, 'de>where
'a: 'b,
pub fn shorten<'b>(self) -> SinkHandle<'b, 'de>where
'a: 'b,
Shortens the lifetime of the handle.
Handles are invariant over their lifetime, this performs the conversion explicitly.
Sourcepub fn ignore_null(self) -> SinkHandle<'a, 'de>
pub fn ignore_null(self) -> SinkHandle<'a, 'de>
Converts the handle into one that ignores null atoms.
When a null atom is received the wrapped sink is not invoked (not even
finish) and the handle turns into a null handle. An
atom counts as null if it is Atom::Null or an extension value which
falls back to null. An empty Atom::Lexical (like the value of
?limit= in a query string) is passed to the wrapped sink, if the
sink rejects it the handle turns into a null handle too.
This is used to implement Option<T>: the slot is set to Some(None)
before the handle of the inner value is created and made to ignore
nulls.
use deser::State;
use deser::de::{Deserialize, SinkHandle};
/// Deserializes like an `Option<T>`.
fn deserialize_optional<'a, 'de, T: Deserialize<'de>>(
out: &'a mut Option<Option<T>>,
state: &mut State,
) -> SinkHandle<'a, 'de> {
T::deserialize_into(out.insert(None), state).ignore_null()
}