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}