Skip to main content

deser_core/de/
slot.rs

1//! The slots of values that are deserialized from atoms.
2use alloc::borrow::Cow;
3use alloc::string::String;
4use core::marker::PhantomData;
5use core::ops::{Deref, DerefMut};
6
7use crate::de::{Deserialize, Sink, SinkHandle};
8use crate::error::Error;
9use crate::event::Atom;
10use crate::state::State;
11
12/// The slot of a value that is deserialized from an atom.
13///
14/// Values that are deserialized from atoms (like numbers or strings) do not
15/// need a sink with state: the sink is the slot itself.  A `Slot<T, A>` is
16/// the slot of a `T` (a transparent wrapper around the `Option<T>`) which
17/// is a [`Sink`] that passes the atoms it receives to
18/// [`A::deserialize_atom`](Deserialize::deserialize_atom).  This is the
19/// sink of the default implementation of
20/// [`Deserialize::deserialize_into`], so values that are deserialized from
21/// atoms only implement [`deserialize_atom`](Deserialize::deserialize_atom)
22/// (and [`expecting`](Deserialize::expecting), which defaults to the name
23/// of the type).  `A` is the type that implements [`Deserialize`], which is
24/// the value itself unless it's an adapter (see
25/// [`adapters`](crate::adapters)).
26///
27/// The slot dereferences to the `Option<T>`, [`set`](Self::set) places a
28/// value in it.  Atoms which are not accepted are passed to
29/// [`default_atom`](crate::de::default_atom) with the slot as sink:
30///
31/// ```
32/// use std::borrow::Cow;
33/// use deser::de::{DeserializeDriver, Slot, default_atom};
34/// use deser::{Atom, Deserialize, Error, State};
35///
36/// struct Celsius(f64);
37///
38/// impl<'de> Deserialize<'de> for Celsius {
39///     fn deserialize_atom(
40///         slot: &mut Slot<Self>,
41///         atom: Atom,
42///         state: &mut State,
43///     ) -> Result<(), Error> {
44///         match atom {
45///             Atom::F64(value) => {
46///                 slot.set(Celsius(value));
47///                 Ok(())
48///             }
49///             other => default_atom(slot, other, state),
50///         }
51///     }
52///
53///     fn expecting() -> Cow<'static, str> {
54///         Cow::Borrowed("temperature")
55///     }
56/// }
57///
58/// let mut out = None::<Celsius>;
59/// DeserializeDriver::new(&mut out).emit(21.5).unwrap();
60/// assert_eq!(out.unwrap().0, 21.5);
61/// ```
62#[repr(transparent)]
63pub struct Slot<T, A = T> {
64    value: Option<T>,
65    // `A` is only used for its functions
66    _marker: PhantomData<fn() -> A>,
67}
68
69impl<T, A> Slot<T, A> {
70    /// Wraps an `Option<T>` in a slot.
71    ///
72    /// This is a cast, the slot is the `Option<T>`.
73    #[inline(always)]
74    pub fn wrap(out: &mut Option<T>) -> &mut Slot<T, A> {
75        // SAFETY: the slot is a transparent wrapper around the option
76        unsafe { &mut *(out as *mut Option<T> as *mut Slot<T, A>) }
77    }
78
79    /// Places a value in the slot.
80    #[inline(always)]
81    pub fn set(&mut self, value: T) {
82        self.value = Some(value);
83    }
84}
85
86impl<'de, T: Send, A: Deserialize<'de, T>> Slot<T, A> {
87    /// Returns a handle to the slot of the `Option<T>`.
88    ///
89    /// Unlike [`SinkHandle::to`] this does not require `A` to outlive the
90    /// handle: `A` is only used for its functions, which cannot hold
91    /// borrowed data (see `SinkHandle::arena_unbounded`).
92    #[inline(always)]
93    pub(crate) fn handle<'a>(out: &'a mut Option<T>) -> SinkHandle<'a, 'de> {
94        // the slot outlives this function (like every type parameter)
95        let sink: *mut (dyn Sink<'de> + '_) = out as *mut Option<T> as *mut Slot<T, A>;
96        // SAFETY: the slot is a transparent wrapper around the option which
97        // is borrowed for the lifetime of the handle.  What `A` stands for
98        // is not used, the sink only invokes the functions of `A`.
99        SinkHandle::to(unsafe {
100            &mut *core::mem::transmute::<*mut (dyn Sink<'de> + '_), *mut (dyn Sink<'de> + 'a)>(sink)
101        })
102    }
103}
104
105impl<T, A> Deref for Slot<T, A> {
106    type Target = Option<T>;
107
108    #[inline(always)]
109    fn deref(&self) -> &Option<T> {
110        &self.value
111    }
112}
113
114impl<T, A> DerefMut for Slot<T, A> {
115    #[inline(always)]
116    fn deref_mut(&mut self) -> &mut Option<T> {
117        &mut self.value
118    }
119}
120
121impl<'de, T: Send, A: Deserialize<'de, T>> Sink<'de> for Slot<T, A> {
122    #[inline]
123    fn atom(&mut self, atom: Atom, state: &mut State) -> Result<(), Error> {
124        A::deserialize_atom(self, atom, state)
125    }
126
127    #[inline]
128    fn borrowed_atom(&mut self, atom: Atom<'de>, state: &mut State) -> Result<(), Error> {
129        A::deserialize_borrowed_atom(self, atom, state)
130    }
131
132    fn expecting(&self) -> Cow<'_, str> {
133        A::expecting()
134    }
135}
136
137/// Removes the module paths from a type name.
138///
139/// This turns `alloc::vec::Vec<my_crate::Point>` into `Vec<Point>`.
140pub(crate) fn short_type_name(name: &'static str) -> Cow<'static, str> {
141    if !name.contains("::") {
142        return Cow::Borrowed(name);
143    }
144    let mut rv = String::with_capacity(name.len());
145    // where the identifier that is written last starts
146    let mut ident_start = 0;
147    let mut rest = name;
148    while let Some(c) = rest.chars().next() {
149        if let Some(after) = rest.strip_prefix("::") {
150            // the identifier was a path segment
151            rv.truncate(ident_start);
152            rest = after;
153            continue;
154        }
155        rv.push(c);
156        if !(c.is_alphanumeric() || c == '_') {
157            ident_start = rv.len();
158        }
159        rest = &rest[c.len_utf8()..];
160    }
161    Cow::Owned(rv)
162}
163
164#[cfg(test)]
165mod tests {
166    use super::short_type_name;
167
168    #[test]
169    fn test_short_type_name() {
170        assert_eq!(short_type_name("u32"), "u32");
171        assert_eq!(short_type_name("my_crate::Point"), "Point");
172        assert_eq!(
173            short_type_name("alloc::vec::Vec<my_crate::geo::Point>"),
174            "Vec<Point>"
175        );
176        assert_eq!(
177            short_type_name("(u8, &alloc::string::String, [a::B; 2])"),
178            "(u8, &String, [B; 2])"
179        );
180        assert_eq!(
181            short_type_name(
182                "core::option::Option<std::collections::hash::map::HashMap<a::K, b::V>>"
183            ),
184            "Option<HashMap<K, V>>"
185        );
186    }
187}