Skip to main content

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>;