miniconf/
tree.rs

1use core::any::Any;
2
3use serde::{Deserializer, Serializer};
4
5use crate::{IntoKeys, Keys, 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> to copy T::SCHEMA
150    const SCHEMA: &Schema;
151}
152
153/// Access any node by keys.
154///
155/// This uses the `dyn Any` trait object.
156///
157/// ```
158/// use core::any::Any;
159/// use miniconf::{Indices, IntoKeys, JsonPath, TreeAny, TreeSchema};
160/// #[derive(TreeSchema, TreeAny, Default)]
161/// struct S {
162///     foo: u32,
163///     bar: [u16; 2],
164/// };
165/// let mut s = S::default();
166///
167/// for key in S::SCHEMA.nodes::<Indices<[_; 2]>, 2>() {
168///     let a = s.ref_any_by_key(key.unwrap().into_keys()).unwrap();
169///     assert!([0u32.type_id(), 0u16.type_id()].contains(&(&*a).type_id()));
170/// }
171///
172/// let val: &mut u16 = s.mut_by_key(&JsonPath(".bar[1]")).unwrap();
173/// *val = 3;
174/// assert_eq!(s.bar[1], 3);
175///
176/// let val: &u16 = s.ref_by_key(&JsonPath(".bar[1]")).unwrap();
177/// assert_eq!(*val, 3);
178/// ```
179pub trait TreeAny: TreeSchema {
180    /// Obtain a reference to a `dyn Any` trait object for a leaf node.
181    fn ref_any_by_key(&self, keys: impl Keys) -> Result<&dyn Any, ValueError>;
182
183    /// Obtain a mutable reference to a `dyn Any` trait object for a leaf node.
184    fn mut_any_by_key(&mut self, keys: impl Keys) -> Result<&mut dyn Any, ValueError>;
185
186    /// Obtain a reference to a leaf of known type by key.
187    #[inline]
188    fn ref_by_key<T: Any>(&self, keys: impl IntoKeys) -> Result<&T, ValueError> {
189        self.ref_any_by_key(keys.into_keys())?
190            .downcast_ref()
191            .ok_or(ValueError::Access("Incorrect type"))
192    }
193
194    /// Obtain a mutable reference to a leaf of known type by key.
195    #[inline]
196    fn mut_by_key<T: Any>(&mut self, keys: impl IntoKeys) -> Result<&mut T, ValueError> {
197        self.mut_any_by_key(keys.into_keys())?
198            .downcast_mut()
199            .ok_or(ValueError::Access("Incorrect type"))
200    }
201}
202
203/// Serialize a leaf node by its keys.
204///
205/// See also [`crate::json_core`] or `crate::postcard` for convenient wrappers using this trait.
206///
207/// # Derive macro
208///
209/// See [`macro@crate::TreeSerialize`].
210/// The derive macro attributes are described in the [`TreeSchema`] trait.
211pub trait TreeSerialize: TreeSchema {
212    /// Serialize a node by keys.
213    ///
214    /// ```
215    /// # #[cfg(feature = "json-core")] {
216    /// use miniconf::{IntoKeys, TreeSchema, TreeSerialize};
217    /// #[derive(TreeSchema, TreeSerialize)]
218    /// struct S {
219    ///     foo: u32,
220    ///     bar: [u16; 2],
221    /// };
222    /// let s = S {
223    ///     foo: 9,
224    ///     bar: [11, 3],
225    /// };
226    /// let mut buf = [0u8; 10];
227    /// let mut ser = serde_json_core::ser::Serializer::new(&mut buf);
228    /// s.serialize_by_key(["bar", "0"].into_keys(), &mut ser).unwrap();
229    /// let len = ser.end();
230    /// assert_eq!(&buf[..len], b"11");
231    /// # }
232    /// ```
233    ///
234    /// # Args
235    /// * `keys`: A `Keys` identifying the node.
236    /// * `ser`: A `Serializer` to to serialize the value.
237    fn serialize_by_key<S: Serializer>(
238        &self,
239        keys: impl Keys,
240        ser: S,
241    ) -> Result<S::Ok, SerdeError<S::Error>>;
242}
243
244/// Deserialize a leaf node by its keys.
245///
246/// See also [`crate::json_core`] or `crate::postcard` for convenient wrappers using this trait.
247///
248/// # Derive macro
249///
250/// See [`macro@crate::TreeDeserialize`].
251/// The derive macro attributes are described in the [`TreeSchema`] trait.
252pub trait TreeDeserialize<'de>: TreeSchema {
253    /// Deserialize a leaf node by its keys.
254    ///
255    /// ```
256    /// # #[cfg(feature = "derive")] {
257    /// use miniconf::{IntoKeys, TreeDeserialize, TreeSchema};
258    /// #[derive(Default, TreeSchema, TreeDeserialize)]
259    /// struct S {
260    ///     foo: u32,
261    ///     bar: [u16; 2],
262    /// };
263    /// let mut s = S::default();
264    /// let mut de = serde_json::de::Deserializer::from_slice(b"7");
265    /// s.deserialize_by_key(["bar", "0"].into_keys(), &mut de).unwrap();
266    /// de.end().unwrap();
267    /// assert_eq!(s.bar[0], 7);
268    /// # }
269    /// ```
270    ///
271    /// # Args
272    /// * `keys`: A `Keys` identifying the node.
273    /// * `de`: A `Deserializer` to deserialize the value.
274    fn deserialize_by_key<D: Deserializer<'de>>(
275        &mut self,
276        keys: impl Keys,
277        de: D,
278    ) -> Result<(), SerdeError<D::Error>>;
279
280    /// Blind deserialize a leaf node by its keys.
281    ///
282    /// This method should succeed at least in those cases where
283    /// `deserialize_by_key()` succeeds.
284    ///
285    /// ```
286    /// # #[cfg(feature = "derive")] {
287    /// use miniconf::{IntoKeys, TreeDeserialize, TreeSchema};
288    /// #[derive(Default, TreeSchema, TreeDeserialize)]
289    /// struct S {
290    ///     foo: u32,
291    ///     bar: [u16; 2],
292    /// };
293    /// let mut de = serde_json::de::Deserializer::from_slice(b"7");
294    /// S::probe_by_key(["bar", "0"].into_keys(), &mut de)
295    ///     .unwrap();
296    /// de.end().unwrap();
297    /// # }
298    /// ```
299    ///
300    /// # Args
301    /// * `keys`: A `Keys` identifying the node.
302    /// * `de`: A `Deserializer` to deserialize the value.
303    fn probe_by_key<D: Deserializer<'de>>(
304        keys: impl Keys,
305        de: D,
306    ) -> Result<(), SerdeError<D::Error>>;
307}
308
309/// Shorthand for owned deserialization through [`TreeDeserialize`].
310pub trait TreeDeserializeOwned: for<'de> TreeDeserialize<'de> {}
311impl<T> TreeDeserializeOwned for T where T: for<'de> TreeDeserialize<'de> {}
312
313// Blanket impls for refs and muts
314
315impl<T: TreeSchema + ?Sized> TreeSchema for &T {
316    const SCHEMA: &'static Schema = T::SCHEMA;
317}
318
319impl<T: TreeSchema + ?Sized> TreeSchema for &mut T {
320    const SCHEMA: &'static Schema = T::SCHEMA;
321}
322
323impl<T: TreeSerialize + ?Sized> TreeSerialize for &T {
324    #[inline]
325    fn serialize_by_key<S: Serializer>(
326        &self,
327        keys: impl Keys,
328        ser: S,
329    ) -> Result<S::Ok, SerdeError<S::Error>> {
330        (**self).serialize_by_key(keys, ser)
331    }
332}
333
334impl<T: TreeSerialize + ?Sized> TreeSerialize for &mut T {
335    #[inline]
336    fn serialize_by_key<S: Serializer>(
337        &self,
338        keys: impl Keys,
339        ser: S,
340    ) -> Result<S::Ok, SerdeError<S::Error>> {
341        (**self).serialize_by_key(keys, ser)
342    }
343}
344
345impl<'de, T: TreeDeserialize<'de> + ?Sized> TreeDeserialize<'de> for &mut T {
346    #[inline]
347    fn deserialize_by_key<D: Deserializer<'de>>(
348        &mut self,
349        keys: impl Keys,
350        de: D,
351    ) -> Result<(), SerdeError<D::Error>> {
352        (**self).deserialize_by_key(keys, de)
353    }
354
355    #[inline]
356    fn probe_by_key<D: Deserializer<'de>>(
357        keys: impl Keys,
358        de: D,
359    ) -> Result<(), SerdeError<D::Error>> {
360        T::probe_by_key(keys, de)
361    }
362}
363
364impl<T: TreeAny + ?Sized> TreeAny for &mut T {
365    #[inline]
366    fn ref_any_by_key(&self, keys: impl Keys) -> Result<&dyn Any, ValueError> {
367        (**self).ref_any_by_key(keys)
368    }
369
370    #[inline]
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}