miniconf/
tree.rs

1use core::any::Any;
2
3use serde::{Deserializer, Serializer};
4
5use crate::{ExactSize, IntoKeys, Keys, NodeIter, Schema, SerdeError, ValueError};
6
7/// Traversal, iteration of keys in a tree.
8///
9/// See also the sub-traits [`TreeSerialize`], [`TreeDeserialize`], [`TreeAny`].
10///
11/// # Keys
12///
13/// There is a one-to-one relationship between nodes and keys.
14/// The keys used to identify nodes support [`Keys`]/[`IntoKeys`]. They can be
15/// obtained from other [`IntoKeys`] through [`Schema::transcode()`].
16/// An iterator of keys for the nodes is available through [`Schema::nodes()`].
17///
18/// * `usize` is modelled after ASN.1 Object Identifiers, see [`crate::Indices`].
19/// * `&str` keys are sequences of names, like path names. When concatenated, they are separated
20///   by some path hierarchy separator, e.g. `'/'`, see [`crate::Path`], or by some more
21///   complex notation, see [`crate::JsonPath`].
22/// * [`crate::Packed`] is a bit-packed compact compressed notation of
23///   hierarchical compound indices.
24/// * See the `scpi` example for how to implement case-insensitive, relative, and abbreviated/partial
25///   matches.
26///
27/// # Derive macros
28///
29/// Derive macros to automatically implement the correct traits on a struct or enum are available through
30/// [`macro@crate::TreeSchema`], [`macro@crate::TreeSerialize`], [`macro@crate::TreeDeserialize`],
31/// and [`macro@crate::TreeAny`].
32/// A shorthand derive macro that derives all four trait implementations is also available at
33/// [`macro@crate::Tree`].
34///
35/// The derive macros support per-field/per-variant attributes to control the derived trait implementations.
36///
37/// ## Rename
38///
39/// The key for named struct fields or enum variants may be changed from the default field ident using
40/// the `rename` derive macro attribute.
41///
42/// ```
43/// use miniconf::{Path, Tree, TreeSchema};
44/// #[derive(Tree, Default)]
45/// struct S {
46///     #[tree(rename = "OTHER")]
47///     a: f32,
48/// };
49/// let name = S::SCHEMA.transcode::<Path<String, '/'>>([0usize]).unwrap();
50/// assert_eq!(name.0.as_str(), "/OTHER");
51/// ```
52///
53/// ## Skip
54///
55/// Named fields/variants may be omitted from the derived `Tree` trait implementations using the
56/// `skip` attribute.
57/// Note that for tuple structs skipping is only supported for terminal fields:
58///
59/// ```
60/// use miniconf::{Tree};
61/// #[derive(Tree)]
62/// struct S(i32, #[tree(skip)] ());
63/// ```
64///
65/// ```compile_fail
66/// use miniconf::{Tree};
67/// #[derive(Tree)]
68/// struct S(#[tree(skip)] (), i32);
69/// ```
70///
71/// ## Type
72///
73/// The type to use when accessing the field/variant through `TreeDeserialize::probe`
74/// can be overridden using the `typ` derive macro attribute (`#[tree(typ="[f32; 4]")]`).
75///
76/// ## Implementation overrides
77///
78/// `#[tree(with=path)]`
79///
80/// This overrides the calls to the child node/variant traits using pub functions
81/// and constants in the module at the given path:
82/// (`SCHEMA`, `serialize_by_key`, `deserialize_by_key`, `probe_by_key`,
83/// `ref_any_by_key`, `mut_any_by_key`).
84///
85/// Also use this to relax bounds and deny operations.
86/// ```
87/// # use miniconf::{SerdeError, Tree, Keys, ValueError, TreeDeserialize};
88/// # use serde::Deserializer;
89/// #[derive(Tree, Default)]
90/// struct S {
91///     #[tree(with=check)]
92///     b: f32,
93/// }
94/// mod check {
95///     use miniconf::{SerdeError, Deserializer, TreeDeserialize, ValueError, Keys};
96///     pub use miniconf::leaf::{SCHEMA, serialize_by_key, probe_by_key, ref_any_by_key, mut_any_by_key};
97///
98///     pub fn deserialize_by_key<'de, D: Deserializer<'de>>(
99///         value: &mut f32,
100///         keys: impl Keys,
101///         de: D
102///     ) -> Result<(), SerdeError<D::Error>> {
103///         let mut new = *value;
104///         new.deserialize_by_key(keys, de)?;
105///         if new < 0.0 {
106///             Err(ValueError::Access("fail").into())
107///         } else {
108///             *value = new;
109///             Ok(())
110///         }
111///     }
112/// }
113/// ```
114///
115/// ### `defer`
116///
117/// The `defer` attribute is a shorthand for `with()` that defers
118/// child trait implementations to a given expression.
119///
120/// # Array
121///
122/// Blanket implementations of the `Tree*` traits are provided for homogeneous arrays
123/// [`[T; N]`](core::array).
124///
125/// # Option
126///
127/// Blanket implementations of the `Tree*` traits are provided for [`Option<T>`].
128///
129/// These implementations do not alter the path hierarchy and do not consume any items from the `keys`
130/// iterators. The `TreeSchema` behavior of an [`Option`] is such that the `None` variant makes the
131/// corresponding part of the tree inaccessible at run-time. It will still be iterated over (e.g.
132/// by [`Schema::nodes()`]) but attempts to access it (e.g. [`TreeSerialize::serialize_by_key()`],
133/// [`TreeDeserialize::deserialize_by_key()`], [`TreeAny::ref_any_by_key()`], or
134/// [`TreeAny::mut_any_by_key()`]) return the special [`ValueError::Absent`].
135///
136/// This is the same behavior as for other `enums` that have the `Tree*` traits derived.
137///
138/// # Tuples
139///
140/// Blanket impementations for the `Tree*` traits are provided for heterogeneous tuples `(T0, T1, ...)`
141/// up to length eight.
142///
143/// # Examples
144///
145/// See the [`crate`] documentation for a longer example showing how the traits and the derive
146/// macros work.
147pub trait TreeSchema {
148    /// Schema for this tree level
149    // Reference for Option<T> and others to copy T::SCHEMA
150    const SCHEMA: &Schema;
151
152    /// Return an exact size iterator of all leaf nodes
153    ///
154    /// This ensures sufficient state depth at compile time.
155    fn nodes<N, const D: usize>() -> ExactSize<NodeIter<N, D>> {
156        const { assert!(D >= Self::SCHEMA.shape().max_depth) }
157        Self::SCHEMA.nodes()
158    }
159}
160
161/// Access any node by keys.
162///
163/// This uses the `dyn Any` trait object.
164///
165/// ```
166/// use core::any::Any;
167/// use miniconf::{Indices, IntoKeys, JsonPath, TreeAny, TreeSchema};
168/// #[derive(TreeSchema, TreeAny, Default)]
169/// struct S {
170///     foo: u32,
171///     bar: [u16; 2],
172/// };
173/// let mut s = S::default();
174///
175/// for key in S::SCHEMA.nodes::<Indices<[_; 2]>, 2>() {
176///     let a = s.ref_any_by_key(key.unwrap().into_keys()).unwrap();
177///     assert!([0u32.type_id(), 0u16.type_id()].contains(&(&*a).type_id()));
178/// }
179///
180/// let val: &mut u16 = s.mut_by_key(JsonPath(".bar[1]")).unwrap();
181/// *val = 3;
182/// assert_eq!(s.bar[1], 3);
183///
184/// let val: &u16 = s.ref_by_key(JsonPath(".bar[1]")).unwrap();
185/// assert_eq!(*val, 3);
186/// ```
187pub trait TreeAny: TreeSchema {
188    /// Obtain a reference to a `dyn Any` trait object for a leaf node.
189    fn ref_any_by_key(&self, keys: impl Keys) -> Result<&dyn Any, ValueError>;
190
191    /// Obtain a mutable reference to a `dyn Any` trait object for a leaf node.
192    fn mut_any_by_key(&mut self, keys: impl Keys) -> Result<&mut dyn Any, ValueError>;
193
194    /// Obtain a reference to a leaf of known type by key.
195    fn ref_by_key<T: Any>(&self, keys: impl IntoKeys) -> Result<&T, ValueError> {
196        self.ref_any_by_key(keys.into_keys())?
197            .downcast_ref()
198            .ok_or(ValueError::Access("Incorrect type"))
199    }
200
201    /// Obtain a mutable reference to a leaf of known type by key.
202    fn mut_by_key<T: Any>(&mut self, keys: impl IntoKeys) -> Result<&mut T, ValueError> {
203        self.mut_any_by_key(keys.into_keys())?
204            .downcast_mut()
205            .ok_or(ValueError::Access("Incorrect type"))
206    }
207}
208
209/// Serialize a leaf node by its keys.
210///
211/// See also [`crate::json_core`] or `crate::postcard` for convenient wrappers using this trait.
212///
213/// # Derive macro
214///
215/// See [`macro@crate::TreeSerialize`].
216/// The derive macro attributes are described in the [`TreeSchema`] trait.
217pub trait TreeSerialize: TreeSchema {
218    /// Serialize a node by keys.
219    ///
220    /// ```
221    /// # #[cfg(feature = "json-core")] {
222    /// use miniconf::{IntoKeys, TreeSchema, TreeSerialize};
223    /// #[derive(TreeSchema, TreeSerialize)]
224    /// struct S {
225    ///     foo: u32,
226    ///     bar: [u16; 2],
227    /// };
228    /// let s = S {
229    ///     foo: 9,
230    ///     bar: [11, 3],
231    /// };
232    /// let mut buf = [0u8; 10];
233    /// let mut ser = serde_json_core::ser::Serializer::new(&mut buf);
234    /// s.serialize_by_key(["bar", "0"].into_keys(), &mut ser).unwrap();
235    /// let len = ser.end();
236    /// assert_eq!(&buf[..len], b"11");
237    /// # }
238    /// ```
239    ///
240    /// # Args
241    /// * `keys`: A `Keys` identifying the node.
242    /// * `ser`: A `Serializer` to to serialize the value.
243    fn serialize_by_key<S: Serializer>(
244        &self,
245        keys: impl Keys,
246        ser: S,
247    ) -> Result<S::Ok, SerdeError<S::Error>>;
248}
249
250/// Deserialize a leaf node by its keys.
251///
252/// See also [`crate::json_core`] or `crate::postcard` for convenient wrappers using this trait.
253///
254/// # Derive macro
255///
256/// See [`macro@crate::TreeDeserialize`].
257/// The derive macro attributes are described in the [`TreeSchema`] trait.
258pub trait TreeDeserialize<'de>: TreeSchema {
259    /// Deserialize a leaf node by its keys.
260    ///
261    /// ```
262    /// # #[cfg(feature = "derive")] {
263    /// use miniconf::{IntoKeys, TreeDeserialize, TreeSchema};
264    /// #[derive(Default, TreeSchema, TreeDeserialize)]
265    /// struct S {
266    ///     foo: u32,
267    ///     bar: [u16; 2],
268    /// };
269    /// let mut s = S::default();
270    /// let mut de = serde_json::de::Deserializer::from_slice(b"7");
271    /// s.deserialize_by_key(["bar", "0"].into_keys(), &mut de).unwrap();
272    /// de.end().unwrap();
273    /// assert_eq!(s.bar[0], 7);
274    /// # }
275    /// ```
276    ///
277    /// # Args
278    /// * `keys`: A `Keys` identifying the node.
279    /// * `de`: A `Deserializer` to deserialize the value.
280    fn deserialize_by_key<D: Deserializer<'de>>(
281        &mut self,
282        keys: impl Keys,
283        de: D,
284    ) -> Result<(), SerdeError<D::Error>>;
285
286    /// Blind deserialize a leaf node by its keys.
287    ///
288    /// This method should succeed at least in those cases where
289    /// `deserialize_by_key()` succeeds.
290    ///
291    /// ```
292    /// # #[cfg(feature = "derive")] {
293    /// use miniconf::{IntoKeys, TreeDeserialize, TreeSchema};
294    /// #[derive(Default, TreeSchema, TreeDeserialize)]
295    /// struct S {
296    ///     foo: u32,
297    ///     bar: [u16; 2],
298    /// };
299    /// let mut de = serde_json::de::Deserializer::from_slice(b"7");
300    /// S::probe_by_key(["bar", "0"].into_keys(), &mut de)
301    ///     .unwrap();
302    /// de.end().unwrap();
303    /// # }
304    /// ```
305    ///
306    /// # Args
307    /// * `keys`: A `Keys` identifying the node.
308    /// * `de`: A `Deserializer` to deserialize the value.
309    fn probe_by_key<D: Deserializer<'de>>(
310        keys: impl Keys,
311        de: D,
312    ) -> Result<(), SerdeError<D::Error>>;
313}
314
315/// Shorthand for owned deserialization through [`TreeDeserialize`].
316pub trait TreeDeserializeOwned: for<'de> TreeDeserialize<'de> {}
317impl<T> TreeDeserializeOwned for T where T: for<'de> TreeDeserialize<'de> {}
318
319// Blanket impls for refs and muts
320
321impl<T: TreeSchema + ?Sized> TreeSchema for &T {
322    const SCHEMA: &'static Schema = T::SCHEMA;
323}
324
325impl<T: TreeSchema + ?Sized> TreeSchema for &mut T {
326    const SCHEMA: &'static Schema = T::SCHEMA;
327}
328
329impl<T: TreeSerialize + ?Sized> TreeSerialize for &T {
330    fn serialize_by_key<S: Serializer>(
331        &self,
332        keys: impl Keys,
333        ser: S,
334    ) -> Result<S::Ok, SerdeError<S::Error>> {
335        (**self).serialize_by_key(keys, ser)
336    }
337}
338
339impl<T: TreeSerialize + ?Sized> TreeSerialize for &mut T {
340    fn serialize_by_key<S: Serializer>(
341        &self,
342        keys: impl Keys,
343        ser: S,
344    ) -> Result<S::Ok, SerdeError<S::Error>> {
345        (**self).serialize_by_key(keys, ser)
346    }
347}
348
349impl<'de, T: TreeDeserialize<'de> + ?Sized> TreeDeserialize<'de> for &mut T {
350    fn deserialize_by_key<D: Deserializer<'de>>(
351        &mut self,
352        keys: impl Keys,
353        de: D,
354    ) -> Result<(), SerdeError<D::Error>> {
355        (**self).deserialize_by_key(keys, de)
356    }
357
358    fn probe_by_key<D: Deserializer<'de>>(
359        keys: impl Keys,
360        de: D,
361    ) -> Result<(), SerdeError<D::Error>> {
362        T::probe_by_key(keys, de)
363    }
364}
365
366impl<T: TreeAny + ?Sized> TreeAny for &mut T {
367    fn ref_any_by_key(&self, keys: impl Keys) -> Result<&dyn Any, ValueError> {
368        (**self).ref_any_by_key(keys)
369    }
370
371    fn mut_any_by_key(&mut self, keys: impl Keys) -> Result<&mut dyn Any, ValueError> {
372        (**self).mut_any_by_key(keys)
373    }
374}