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 (see [`adapted`](crate::adapted)).
91    #[inline(always)]
92    pub(crate) fn handle<'a>(out: &'a mut Option<T>) -> SinkHandle<'a, 'de> {
93        crate::adapted::slot_sink::<T, A>(out)
94    }
95}
96
97impl<T, A> Deref for Slot<T, A> {
98    type Target = Option<T>;
99
100    #[inline(always)]
101    fn deref(&self) -> &Option<T> {
102        &self.value
103    }
104}
105
106impl<T, A> DerefMut for Slot<T, A> {
107    #[inline(always)]
108    fn deref_mut(&mut self) -> &mut Option<T> {
109        &mut self.value
110    }
111}
112
113impl<'de, T: Send, A: Deserialize<'de, T>> Sink<'de> for Slot<T, A> {
114    #[inline]
115    fn atom(&mut self, atom: Atom, state: &mut State) -> Result<(), Error> {
116        A::deserialize_atom(self, atom, state)
117    }
118
119    #[inline]
120    fn borrowed_atom(&mut self, atom: Atom<'de>, state: &mut State) -> Result<(), Error> {
121        A::deserialize_borrowed_atom(self, atom, state)
122    }
123
124    fn expecting(&self) -> Cow<'_, str> {
125        A::expecting()
126    }
127}
128
129/// Removes the module paths from a type name.
130///
131/// This turns `alloc::vec::Vec<my_crate::Point>` into `Vec<Point>`.
132pub(crate) fn short_type_name(name: &'static str) -> Cow<'static, str> {
133    if !name.contains("::") {
134        return Cow::Borrowed(name);
135    }
136    let mut rv = String::with_capacity(name.len());
137    // where the identifier that is written last starts
138    let mut ident_start = 0;
139    let mut rest = name;
140    while let Some(c) = rest.chars().next() {
141        if let Some(after) = rest.strip_prefix("::") {
142            // the identifier was a path segment
143            rv.truncate(ident_start);
144            rest = after;
145            continue;
146        }
147        rv.push(c);
148        if !(c.is_alphanumeric() || c == '_') {
149            ident_start = rv.len();
150        }
151        rest = &rest[c.len_utf8()..];
152    }
153    Cow::Owned(rv)
154}
155
156#[cfg(test)]
157mod tests {
158    use super::short_type_name;
159
160    #[test]
161    fn test_short_type_name() {
162        assert_eq!(short_type_name("u32"), "u32");
163        assert_eq!(short_type_name("my_crate::Point"), "Point");
164        assert_eq!(
165            short_type_name("alloc::vec::Vec<my_crate::geo::Point>"),
166            "Vec<Point>"
167        );
168        assert_eq!(
169            short_type_name("(u8, &alloc::string::String, [a::B; 2])"),
170            "(u8, &String, [B; 2])"
171        );
172        assert_eq!(
173            short_type_name(
174                "core::option::Option<std::collections::hash::map::HashMap<a::K, b::V>>"
175            ),
176            "Option<HashMap<K, V>>"
177        );
178    }
179}