deser_core/hints.rs
1//! Well-known formatting hints.
2//!
3//! Hints tell formats how a value would like to be presented. They are not
4//! part of the data model and never change the value: formats which do not
5//! have a choice (or do not support a hint) ignore them. Hints are
6//! [event data](crate::State::event) which is attached to the first event of
7//! a value. They are set by values (for instance through the adapters of
8//! this module) or by [layers](crate::ser::Layer), which allows to set them
9//! by path. The last hint set wins, so hints set by layers take precedence
10//! over the ones of the values.
11//!
12//! | Hint | Honored by |
13//! |------------|-------------------------------------------------------------------------------------------|
14//! | [`Layout`] | TOML (inline tables and arrays of tables), YAML (flow style), JSON and XML (single line when indented) |
15//!
16//! Formats can define their own hints and adapters for them with [`Hint`]
17//! and [`Hinted`].
18//!
19//! ```
20//! use std::collections::BTreeMap;
21//! use deser::Serialize;
22//! use deser::hints::Compact;
23//!
24//! #[derive(Serialize)]
25//! struct Config {
26//! #[deser(as = Compact)]
27//! point: BTreeMap<String, u32>,
28//! }
29//! ```
30use alloc::borrow::Cow;
31use alloc::vec::Vec;
32use core::marker::PhantomData;
33
34use crate::State;
35use crate::adapters::Same;
36use crate::de::{Deserialize, SinkHandle};
37use crate::error::Error;
38use crate::event::{Atom, ContainerShape};
39use crate::ser::{Begin, Describe, Emit, Serialize};
40
41/// How a map or sequence is laid out by formats that have a choice.
42///
43/// ```
44/// use deser::hints::Layout;
45/// # let mut driver = deser::ser::SerializeDriver::new(&());
46/// # let state = driver.state_mut();
47///
48/// Layout::Compact.set(state);
49/// assert_eq!(Layout::of(state), Layout::Compact);
50/// ```
51#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
52#[non_exhaustive]
53pub enum Layout {
54 /// No preference, the format decides.
55 #[default]
56 Auto,
57 /// Keep the container compact, for instance on a single line (a flow
58 /// collection in YAML, an inline table in TOML).
59 Compact,
60 /// Spread the container out, for instance one entry per line (a block
61 /// collection in YAML, a section in TOML).
62 Expanded,
63}
64
65impl Layout {
66 /// Returns the layout of the current event.
67 #[inline]
68 pub fn of(state: &State) -> Layout {
69 state.event::<Layout>().copied().unwrap_or_default()
70 }
71
72 /// Sets the layout of the current event.
73 ///
74 /// This is intended to be called from
75 /// [`Serialize::serialize`] or a
76 /// [`Layer`](crate::ser::Layer), the layout applies to the value that is
77 /// serialized.
78 #[inline]
79 pub fn set(self, state: &mut State) {
80 *state.event_mut::<Layout>() = self;
81 }
82}
83
84/// A hint that can be set by the [`Hinted`] adapter.
85///
86/// Hints are types which set some [event data](crate::State::event) for
87/// the value that is serialized. Formats that define their own hints can
88/// use this to provide adapters for them:
89///
90/// ```
91/// use deser::State;
92/// use deser::hints::{Hint, Hinted};
93///
94/// #[derive(Debug, Default, Clone)]
95/// pub struct Emphasis(pub bool);
96///
97/// /// Sets the emphasis hint.
98/// pub struct Emphasized;
99///
100/// impl Hint for Emphasized {
101/// fn set(state: &mut State) {
102/// state.event_mut::<Emphasis>().0 = true;
103/// }
104/// }
105///
106/// /// The adapter: `#[deser(as = Emphasize)]`.
107/// pub type Emphasize<A = deser::adapters::Same> = Hinted<Emphasized, A>;
108/// ```
109pub trait Hint: 'static {
110 /// Sets the hint for the value that is serialized.
111 fn set(state: &mut State);
112}
113
114/// An adapter which sets a [`Hint`] and serializes the value with another
115/// adapter.
116///
117/// This is an adapter (see [`adapters`](crate::adapters)) for all types
118/// that the adapter `A` supports, by default ([`Same`]) the value is
119/// serialized with its own [`Serialize`] implementation.
120/// It's transparent when deserializing. [`Compact`] and [`Expanded`] are
121/// such adapters: `Compact<Vec<Base64>>` serializes a `Vec<Vec<u8>>` as
122/// base64 strings with [`Layout::Compact`].
123pub struct Hinted<H, A = Same>(PhantomData<fn() -> (H, A)>);
124
125impl<T: ?Sized, H: Hint, A: Serialize<T>> Serialize<T> for Hinted<H, A> {
126 #[inline]
127 fn serialize<'a>(value: &'a T, state: &mut State) -> Result<Emit<'a>, Error> {
128 H::set(state);
129 A::serialize(value, state)
130 }
131
132 #[inline]
133 fn finish(value: &T, state: &mut State) -> Result<(), Error> {
134 A::finish(value, state)
135 }
136
137 #[inline]
138 fn is_optional(value: &T) -> bool {
139 A::is_optional(value)
140 }
141
142 #[inline]
143 fn container_shape(value: &T) -> ContainerShape {
144 A::container_shape(value)
145 }
146
147 fn describe(value: &T, d: &mut dyn Describe) {
148 A::describe(value, d)
149 }
150
151 #[inline]
152 fn __private_begin<'a>(value: &'a T, state: &mut State) -> Result<Begin<'a>, Error> {
153 H::set(state);
154 A::__private_begin(value, state)
155 }
156
157 #[inline]
158 fn __private_slice_as_bytes(val: &[T]) -> Option<Cow<'_, [u8]>>
159 where
160 T: Sized,
161 {
162 A::__private_slice_as_bytes(val)
163 }
164}
165
166impl<'de, T: Send, H: Hint, A: Deserialize<'de, T>> Deserialize<'de, T> for Hinted<H, A> {
167 #[inline]
168 fn deserialize_into<'out>(
169 out: &'out mut Option<T>,
170 state: &mut State,
171 ) -> SinkHandle<'out, 'de> {
172 A::deserialize_into(out, state)
173 }
174
175 fn expecting() -> Cow<'static, str> {
176 A::expecting()
177 }
178
179 fn describe_type(d: &mut dyn Describe) {
180 A::describe_type(d)
181 }
182
183 #[inline]
184 fn initial_value() -> Option<T> {
185 A::initial_value()
186 }
187
188 #[inline]
189 fn __private_atom_into(
190 out: &mut Option<T>,
191 atom: Atom,
192 state: &mut State,
193 ) -> Result<(), Error> {
194 A::__private_atom_into(out, atom, state)
195 }
196
197 #[inline]
198 fn __private_borrowed_atom_into(
199 out: &mut Option<T>,
200 atom: Atom<'de>,
201 state: &mut State,
202 ) -> Result<(), Error> {
203 A::__private_borrowed_atom_into(out, atom, state)
204 }
205
206 #[inline]
207 fn __private_is_bytes() -> bool {
208 A::__private_is_bytes()
209 }
210
211 #[inline]
212 fn __private_vec_from_bytes(bytes: Vec<u8>) -> Option<Vec<T>> {
213 A::__private_vec_from_bytes(bytes)
214 }
215
216 #[inline]
217 fn __private_array_from_bytes<const N: usize>(bytes: &[u8]) -> Option<[T; N]> {
218 A::__private_array_from_bytes(bytes)
219 }
220
221 #[inline(always)]
222 fn __private_raw() -> Option<&'static crate::ext::RawFormatInfo> {
223 A::__private_raw()
224 }
225
226 #[inline]
227 fn __private_collects() -> bool {
228 A::__private_collects()
229 }
230
231 #[inline]
232 fn __private_collect_into<'out>(
233 out: &'out mut Option<T>,
234 state: &mut State,
235 ) -> SinkHandle<'out, 'de> {
236 A::__private_collect_into(out, state)
237 }
238
239 #[inline]
240 fn __private_collect_update<'out>(
241 value: &'out mut T,
242 first: bool,
243 state: &mut State,
244 ) -> SinkHandle<'out, 'de> {
245 A::__private_collect_update(value, first, state)
246 }
247
248 #[inline]
249 fn __private_collect_empty() -> Option<T> {
250 A::__private_collect_empty()
251 }
252}
253
254/// The [`Hint`] for [`Layout::Compact`].
255pub struct CompactLayout;
256
257impl Hint for CompactLayout {
258 #[inline]
259 fn set(state: &mut State) {
260 Layout::Compact.set(state);
261 }
262}
263
264/// The [`Hint`] for [`Layout::Expanded`].
265pub struct ExpandedLayout;
266
267impl Hint for ExpandedLayout {
268 #[inline]
269 fn set(state: &mut State) {
270 Layout::Expanded.set(state);
271 }
272}
273
274/// Serializes a value with [`Layout::Compact`].
275///
276/// See [`Hinted`], `Compact<A>` uses the adapter `A` for the value.
277pub type Compact<A = Same> = Hinted<CompactLayout, A>;
278
279/// Serializes a value with [`Layout::Expanded`].
280///
281/// See [`Hinted`], `Expanded<A>` uses the adapter `A` for the value.
282pub type Expanded<A = Same> = Hinted<ExpandedLayout, A>;