Skip to main content

deser_core/ser/
chunk.rs

1use crate::event::{Atom, Bytes};
2use crate::ser::boxed::unsize;
3use crate::ser::{Boxed, MapEmitter, SeqEmitter, SerializeHandle, StructEmitter};
4use crate::{State, Text};
5use alloc::string::String;
6
7/// A chunk represents the minimum state necessary to serialize a value.
8///
9/// Chunks are of two types: atomic primitives and stateful emitters.
10/// For instance `Chunk::Bool(true)` is an atomic primitive.  It can be emitted
11/// to a serializer directly.  On the other hand a `Chunk::Map` contains a
12/// stateful emitter that keeps yielding values until it's done walking over
13/// the map.
14///
15/// The emitters are typically allocated in the arena of the serialization
16/// with [`Chunk::seq`], [`Chunk::map`] and [`Chunk::structure`] (see
17/// [`Boxed`]).
18pub enum Chunk<'a> {
19    Atom(Atom<'a>),
20    Struct(Boxed<dyn StructEmitter + 'a>),
21    Map(Boxed<dyn MapEmitter + 'a>),
22    Seq(Boxed<dyn SeqEmitter + 'a>),
23    /// Serializes another value in place of this one.
24    ///
25    /// The driver serializes the value in the handle as if it was produced
26    /// instead of the value that returned the chunk.  This is useful to
27    /// serialize a value by converting it into another value first as the
28    /// handle can own that value:
29    ///
30    /// ```
31    /// use deser::ser::{Chunk, Serialize, SerializeHandle};
32    /// use deser::{Error, State};
33    ///
34    /// struct Point(u32, u32);
35    ///
36    /// impl Serialize for Point {
37    ///     fn serialize(&self, state: &mut State) -> Result<Chunk<'_>, Error> {
38    ///         // serialize as a vector
39    ///         Ok(Chunk::Forward(SerializeHandle::arena(
40    ///             vec![self.0, self.1],
41    ///             state,
42    ///         )))
43    ///     }
44    /// }
45    /// ```
46    ///
47    /// The [`container_shape`](crate::ser::Serialize::container_shape) of the
48    /// value that returned the chunk is not used, the forwarded value provides
49    /// its own.
50    /// [`finish`](crate::ser::Serialize::finish) is invoked on the forwarded
51    /// value first and then on the value that returned the chunk.
52    ///
53    /// Forwarding chunks cannot be flattened into structs.
54    Forward(SerializeHandle<'a>),
55}
56
57impl<'a> Chunk<'a> {
58    /// Creates a chunk of a sequence emitter in the arena of the
59    /// serialization.
60    #[inline(always)]
61    pub fn seq<E: SeqEmitter + 'a>(emitter: E, state: &mut State) -> Chunk<'a> {
62        Chunk::Seq(unsize(Boxed::arena(emitter, state), |x| {
63            x as *mut (dyn SeqEmitter + 'a)
64        }))
65    }
66
67    /// Creates a chunk of a map emitter in the arena of the serialization.
68    #[inline(always)]
69    pub fn map<E: MapEmitter + 'a>(emitter: E, state: &mut State) -> Chunk<'a> {
70        Chunk::Map(unsize(Boxed::arena(emitter, state), |x| {
71            x as *mut (dyn MapEmitter + 'a)
72        }))
73    }
74
75    /// Creates a chunk of a struct emitter in the arena of the
76    /// serialization.
77    #[inline(always)]
78    pub fn structure<E: StructEmitter + 'a>(emitter: E, state: &mut State) -> Chunk<'a> {
79        Chunk::Struct(unsize(Boxed::arena(emitter, state), |x| {
80            x as *mut (dyn StructEmitter + 'a)
81        }))
82    }
83}
84
85impl<'a> From<Atom<'a>> for Chunk<'a> {
86    fn from(atom: Atom<'a>) -> Self {
87        Chunk::Atom(atom)
88    }
89}
90
91macro_rules! impl_from {
92    ($ty:ty, $atom:ident) => {
93        impl From<$ty> for Chunk<'static> {
94            fn from(value: $ty) -> Self {
95                Chunk::Atom(Atom::$atom(value as _))
96            }
97        }
98    };
99}
100
101impl_from!(u64, U64);
102impl_from!(i64, I64);
103impl_from!(usize, U64);
104impl_from!(isize, I64);
105impl_from!(bool, Bool);
106impl_from!(char, Char);
107
108impl From<f64> for Chunk<'static> {
109    fn from(value: f64) -> Self {
110        Chunk::Atom(Atom::F64(value))
111    }
112}
113
114impl From<f32> for Chunk<'static> {
115    fn from(value: f32) -> Self {
116        Chunk::Atom(Atom::F32(value))
117    }
118}
119
120impl From<()> for Chunk<'static> {
121    fn from(_: ()) -> Chunk<'static> {
122        Chunk::Atom(Atom::Null)
123    }
124}
125
126impl<'a> From<&'a str> for Chunk<'a> {
127    fn from(value: &'a str) -> Chunk<'a> {
128        Chunk::Atom(Atom::Str(Text::borrowed(value)))
129    }
130}
131
132impl<'a> From<&'a [u8]> for Chunk<'a> {
133    fn from(value: &'a [u8]) -> Chunk<'a> {
134        Chunk::Atom(Atom::Bytes(Bytes::borrowed(value)))
135    }
136}
137
138impl From<String> for Chunk<'static> {
139    fn from(value: String) -> Chunk<'static> {
140        Chunk::Atom(Atom::Str(Text::owned(value)))
141    }
142}
143
144#[cfg(target_pointer_width = "64")]
145const _: () = assert!(core::mem::size_of::<Chunk<'static>>() == 32);
146#[cfg(target_pointer_width = "32")]
147const _: () = assert!(core::mem::size_of::<Chunk<'static>>() == 24);