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}