miniconf

Trait TreeKey

source
pub trait TreeKey {
    // Required methods
    fn traverse_all<W: Walk>() -> Result<W, W::Error>;
    fn traverse_by_key<K, F, E>(keys: K, func: F) -> Result<usize, Error<E>>
       where K: Keys,
             F: FnMut(usize, Option<&'static str>, NonZero<usize>) -> Result<(), E>;

    // Provided methods
    fn transcode<N, K>(keys: K) -> Result<(N, Node), Traversal>
       where K: IntoKeys,
             N: Transcode + Default { ... }
    fn nodes<N, const D: usize>() -> NodeIter<Self, N, D> 
       where N: Transcode + Default { ... }
}
Expand description

Traversal, iteration of keys in a tree.

See also the sub-traits TreeSerialize, TreeDeserialize, TreeAny.

§Keys

There is a one-to-one relationship between nodes and keys. The keys used to identify nodes support Keys/IntoKeys. They can be obtained from other IntoKeys through Transcode/TreeKey::transcode(). An iterator of keys for the nodes is available through TreeKey::nodes()/NodeIter.

  • usize is modelled after ASN.1 Object Identifiers, see crate::Indices.
  • &str keys are sequences of names, like path names. When concatenated, they are separated by some path hierarchy separator, e.g. '/', see crate::Path, or by some more complex notation, see crate::JsonPath.
  • crate::Packed is a bit-packed compact compressed notation of hierarchical compound indices.
  • See the scpi example for how to implement case-insensitive, relative, and abbreviated/partial matches.

§Derive macros

Derive macros to automatically implement the correct traits on a struct or enum are available through crate::TreeKey, crate::TreeSerialize, crate::TreeDeserialize, and crate::TreeAny. A shorthand derive macro that derives all four trait implementations is also available at crate::Tree.

The derive macros support per-field/per-variant attributes to control the derived trait implementations.

§Rename

The key for named struct fields or enum variants may be changed from the default field ident using the rename derive macro attribute.

use miniconf::{Leaf, Path, Tree, TreeKey};
#[derive(Tree, Default)]
struct S {
    #[tree(rename = "OTHER")]
    a: Leaf<f32>,
};
let (name, _node) = S::transcode::<Path<String, '/'>, _>([0usize]).unwrap();
assert_eq!(name.as_str(), "/OTHER");

§Skip

Named fields/variants may be omitted from the derived Tree trait implementations using the skip attribute. Note that for tuple structs skipping is only supported for terminal fields:

use miniconf::{Leaf, Tree};
#[derive(Tree)]
struct S(Leaf<i32>, #[tree(skip)] ());
use miniconf::{Tree, Leaf};
#[derive(Tree)]
struct S(#[tree(skip)] (), Leaf<i32>);

§Type

The type to use when accessing the field through TreeKey can be overridden using the typ derive macro attribute (#[tree(typ="[f32; 4]")]).

§Accessors

The get, get_mut, validate callbacks can be used to implement accessors, validation or support remote types (e.g. #[tree(get_mut=func())])

§get

The getter is called during serialize_by_key() before leaf serialization and during ref_any_by_key(). Its signature is fn() -> Result<&T, &'static str>. The default getter is Ok(&self.field). &self is in scope and can be used. If a getter returns an error message Err(&str) the serialization/traversal is not performed, further getters at greater depth are not invoked and Traversal::Access is returned.

§get_mut

get_mut is invoked during mut_any_by_key() and during deserialize_by_key() before deserialization while traversing down to the leaf node. The signature is fn() -> Result<&mut T, &str>. &mut self is in scope and can be used/mutated. The default get_mut is Ok(&mut self.field). If get_mut returns an Err Traversal::Access will be returned.

§validate

validate is called after the successful update of the leaf field during upward traversal. The validate signature is fn(depth: usize) -> Result<usize, &'static str>. &mut self is in scope and can be used/mutated. If a validate callback returns Err(), the leaf value already has been updated and Traversal::Invalid is returned from deserialize_by_key().

use miniconf::{Error, Leaf, Tree};
#[derive(Tree, Default)]
struct S {
    #[tree(validate=self.non_leaf)]
    b: [Leaf<f32>; 2],
};
impl S {
    fn non_leaf(&mut self, depth: usize) -> Result<usize, &'static str> {
        Err("fail")
    }
}

§defer

The defer attribute is a shorthand for get+get_mut of the same owned value.

§Array

Blanket implementations of the Tree* traits are provided for homogeneous arrays [T; N].

§Option

Blanket implementations of the Tree* traits are provided for Option<T>.

These implementations do not alter the path hierarchy and do not consume any items from the keys iterators. The TreeKey behavior of an Option is such that the None variant makes the corresponding part of the tree inaccessible at run-time. It will still be iterated over (e.g. by TreeKey::nodes()) but attempts to access it (e.g. TreeSerialize::serialize_by_key(), TreeDeserialize::deserialize_by_key(), TreeAny::ref_any_by_key(), or TreeAny::mut_any_by_key()) return the special Traversal::Absent.

This is the same behavior as for other enums that have the Tree* traits derived.

§Tuples

Blanket impementations for the Tree* traits are provided for heterogeneous tuples (T0, T1, ...) up to length eight.

§Examples

See the crate documentation for a longer example showing how the traits and the derive macros work.

Required Methods§

source

fn traverse_all<W: Walk>() -> Result<W, W::Error>

Walk metadata about all paths.

use miniconf::{Leaf, Metadata, TreeKey};
#[derive(TreeKey)]
struct S {
    foo: Leaf<u32>,
    bar: [Leaf<u16>; 2],
};
let m: Metadata = S::traverse_all().unwrap();
assert_eq!((m.max_depth, m.max_length, m.count.get()), (2, 4, 3));
source

fn traverse_by_key<K, F, E>(keys: K, func: F) -> Result<usize, Error<E>>
where K: Keys, F: FnMut(usize, Option<&'static str>, NonZero<usize>) -> Result<(), E>,

Traverse from the root to a leaf and call a function for each node.

If a leaf is found early (keys being longer than required) Err(Traversal(TooLong(depth))) is returned. If keys is exhausted before reaching a leaf node, Err(Traversal(TooShort(depth))) is returned. Traversal::Access/Invalid/Absent/Finalization are never returned.

use miniconf::{IntoKeys, Leaf, TreeKey};
#[derive(TreeKey)]
struct S {
    foo: Leaf<u32>,
    bar: [Leaf<u16>; 2],
};
let mut ret = [(1, Some("bar"), 2), (0, None, 2)].into_iter();
let func = |index, name, len: core::num::NonZero<usize>| -> Result<(), ()> {
    assert_eq!(ret.next().unwrap(), (index, name, len.get()));
    Ok(())
};
assert_eq!(S::traverse_by_key(["bar", "0"].into_keys(), func), Ok(2));
§Args
  • keys: An Iterator of Keys identifying the node.
  • func: A FnMut to be called for each (internal and leaf) node on the path. Its arguments are the index and the optional name of the node and the number of top-level nodes at the given depth. Returning Err(E) aborts the traversal. Returning Ok(()) continues the downward traversal.
§Returns

Node depth on success (number of keys consumed/number of calls to func)

§Design note

Writing this to return an iterator instead of using a callback would have worse performance (O(n^2) instead of O(n) for matching)

Provided Methods§

source

fn transcode<N, K>(keys: K) -> Result<(N, Node), Traversal>
where K: IntoKeys, N: Transcode + Default,

Transcode keys to a new keys type representation

The keys can be

  • too short: the internal node is returned
  • matched length: the leaf node is returned
  • too long: Err(TooLong(depth)) is returned

In order to not require N: Default, use Transcode::transcode on an existing &mut N.

use miniconf::{Indices, JsonPath, Leaf, Node, Packed, Path, TreeKey};
#[derive(TreeKey)]
struct S {
    foo: Leaf<u32>,
    bar: [Leaf<u16>; 5],
};

let idx = [1, 1];

let (path, node) = S::transcode::<Path<String, '/'>, _>(idx).unwrap();
assert_eq!(path.as_str(), "/bar/1");
let (path, node) = S::transcode::<JsonPath<String>, _>(idx).unwrap();
assert_eq!(path.as_str(), ".bar[1]");
let (indices, node) = S::transcode::<Indices<[_; 2]>, _>(&path).unwrap();
assert_eq!(&indices[..node.depth()], idx);
let (indices, node) = S::transcode::<Indices<[_; 2]>, _>(["bar", "1"]).unwrap();
assert_eq!(&indices[..node.depth()], [1, 1]);
let (packed, node) = S::transcode::<Packed, _>(["bar", "4"]).unwrap();
assert_eq!(packed.into_lsb().get(), 0b1_1_100);
let (path, node) = S::transcode::<Path<String, '/'>, _>(packed).unwrap();
assert_eq!(path.as_str(), "/bar/4");
let ((), node) = S::transcode(&path).unwrap();
assert_eq!(node, Node::leaf(2));
§Args
  • keys: IntoKeys to identify the node.
§Returns

Transcoded target and node information on success

source

fn nodes<N, const D: usize>() -> NodeIter<Self, N, D>
where N: Transcode + Default,

Return an iterator over nodes of a given type

This is a walk of all leaf nodes. The iterator will walk all paths, including those that may be absent at runtime (see TreeKey). An iterator with an exact and trusted size_hint() can be obtained from this through NodeIter::exact_size(). The D const generic of NodeIter is the maximum key depth.

use miniconf::{Indices, JsonPath, Leaf, Node, Packed, Path, TreeKey};
#[derive(TreeKey)]
struct S {
    foo: Leaf<u32>,
    bar: [Leaf<u16>; 2],
};

let paths: Vec<_> = S::nodes::<Path<String, '/'>, 2>()
    .exact_size()
    .map(|p| p.unwrap().0.into_inner())
    .collect();
assert_eq!(paths, ["/foo", "/bar/0", "/bar/1"]);

let paths: Vec<_> = S::nodes::<JsonPath<String>, 2>()
    .exact_size()
    .map(|p| p.unwrap().0.into_inner())
    .collect();
assert_eq!(paths, [".foo", ".bar[0]", ".bar[1]"]);

let indices: Vec<_> = S::nodes::<Indices<[_; 2]>, 2>()
    .exact_size()
    .map(|p| {
        let (idx, node) = p.unwrap();
        (idx.into_inner(), node.depth)
    })
    .collect();
assert_eq!(indices, [([0, 0], 1), ([1, 0], 2), ([1, 1], 2)]);

let packed: Vec<_> = S::nodes::<Packed, 2>()
    .exact_size()
    .map(|p| p.unwrap().0.into_lsb().get())
    .collect();
assert_eq!(packed, [0b1_0, 0b1_1_0, 0b1_1_1]);

let nodes: Vec<_> = S::nodes::<(), 2>()
    .exact_size()
    .map(|p| p.unwrap().1)
    .collect();
assert_eq!(nodes, [Node::leaf(1), Node::leaf(2), Node::leaf(2)]);

Object Safety§

This trait is not object safe.

Implementations on Foreign Types§

source§

impl<T0: TreeKey> TreeKey for (T0,)

source§

fn traverse_all<W: Walk>() -> Result<W, W::Error>

source§

fn traverse_by_key<K, F, E>(keys: K, func: F) -> Result<usize, Error<E>>
where K: Keys, F: FnMut(usize, Option<&'static str>, NonZero<usize>) -> Result<(), E>,

source§

impl<T0: TreeKey, T1: TreeKey> TreeKey for (T0, T1)

source§

fn traverse_all<W: Walk>() -> Result<W, W::Error>

source§

fn traverse_by_key<K, F, E>(keys: K, func: F) -> Result<usize, Error<E>>
where K: Keys, F: FnMut(usize, Option<&'static str>, NonZero<usize>) -> Result<(), E>,

source§

impl<T0: TreeKey, T1: TreeKey, T2: TreeKey> TreeKey for (T0, T1, T2)

source§

fn traverse_all<W: Walk>() -> Result<W, W::Error>

source§

fn traverse_by_key<K, F, E>(keys: K, func: F) -> Result<usize, Error<E>>
where K: Keys, F: FnMut(usize, Option<&'static str>, NonZero<usize>) -> Result<(), E>,

source§

impl<T0: TreeKey, T1: TreeKey, T2: TreeKey, T3: TreeKey> TreeKey for (T0, T1, T2, T3)

source§

fn traverse_all<W: Walk>() -> Result<W, W::Error>

source§

fn traverse_by_key<K, F, E>(keys: K, func: F) -> Result<usize, Error<E>>
where K: Keys, F: FnMut(usize, Option<&'static str>, NonZero<usize>) -> Result<(), E>,

source§

impl<T0: TreeKey, T1: TreeKey, T2: TreeKey, T3: TreeKey, T4: TreeKey> TreeKey for (T0, T1, T2, T3, T4)

source§

fn traverse_all<W: Walk>() -> Result<W, W::Error>

source§

fn traverse_by_key<K, F, E>(keys: K, func: F) -> Result<usize, Error<E>>
where K: Keys, F: FnMut(usize, Option<&'static str>, NonZero<usize>) -> Result<(), E>,

source§

impl<T0: TreeKey, T1: TreeKey, T2: TreeKey, T3: TreeKey, T4: TreeKey, T5: TreeKey> TreeKey for (T0, T1, T2, T3, T4, T5)

source§

fn traverse_all<W: Walk>() -> Result<W, W::Error>

source§

fn traverse_by_key<K, F, E>(keys: K, func: F) -> Result<usize, Error<E>>
where K: Keys, F: FnMut(usize, Option<&'static str>, NonZero<usize>) -> Result<(), E>,

source§

impl<T0: TreeKey, T1: TreeKey, T2: TreeKey, T3: TreeKey, T4: TreeKey, T5: TreeKey, T6: TreeKey> TreeKey for (T0, T1, T2, T3, T4, T5, T6)

source§

fn traverse_all<W: Walk>() -> Result<W, W::Error>

source§

fn traverse_by_key<K, F, E>(keys: K, func: F) -> Result<usize, Error<E>>
where K: Keys, F: FnMut(usize, Option<&'static str>, NonZero<usize>) -> Result<(), E>,

source§

impl<T0: TreeKey, T1: TreeKey, T2: TreeKey, T3: TreeKey, T4: TreeKey, T5: TreeKey, T6: TreeKey, T7: TreeKey> TreeKey for (T0, T1, T2, T3, T4, T5, T6, T7)

source§

fn traverse_all<W: Walk>() -> Result<W, W::Error>

source§

fn traverse_by_key<K, F, E>(keys: K, func: F) -> Result<usize, Error<E>>
where K: Keys, F: FnMut(usize, Option<&'static str>, NonZero<usize>) -> Result<(), E>,

source§

impl<T: TreeKey> TreeKey for Bound<T>

source§

fn traverse_all<W: Walk>() -> Result<W, W::Error>

source§

fn traverse_by_key<K, F, G>(keys: K, func: F) -> Result<usize, Error<G>>
where K: Keys, F: FnMut(usize, Option<&'static str>, NonZero<usize>) -> Result<(), G>,

source§

impl<T: TreeKey> TreeKey for Option<T>

source§

fn traverse_all<W: Walk>() -> Result<W, W::Error>

source§

fn traverse_by_key<K, F, E>(keys: K, func: F) -> Result<usize, Error<E>>
where K: Keys, F: FnMut(usize, Option<&'static str>, NonZero<usize>) -> Result<(), E>,

source§

impl<T: TreeKey> TreeKey for &T

source§

fn traverse_all<W: Walk>() -> Result<W, W::Error>

source§

fn traverse_by_key<K, F, E>(keys: K, func: F) -> Result<usize, Error<E>>
where K: Keys, F: FnMut(usize, Option<&'static str>, NonZero<usize>) -> Result<(), E>,

source§

impl<T: TreeKey> TreeKey for &mut T

source§

fn traverse_all<W: Walk>() -> Result<W, W::Error>

source§

fn traverse_by_key<K, F, E>(keys: K, func: F) -> Result<usize, Error<E>>
where K: Keys, F: FnMut(usize, Option<&'static str>, NonZero<usize>) -> Result<(), E>,

source§

impl<T: TreeKey> TreeKey for Cell<T>

source§

fn traverse_all<W: Walk>() -> Result<W, W::Error>

source§

fn traverse_by_key<K, F, E>(keys: K, func: F) -> Result<usize, Error<E>>
where K: Keys, F: FnMut(usize, Option<&'static str>, NonZero<usize>) -> Result<(), E>,

source§

impl<T: TreeKey> TreeKey for RefCell<T>

source§

fn traverse_all<W: Walk>() -> Result<W, W::Error>

source§

fn traverse_by_key<K, F, E>(keys: K, func: F) -> Result<usize, Error<E>>
where K: Keys, F: FnMut(usize, Option<&'static str>, NonZero<usize>) -> Result<(), E>,

source§

impl<T: TreeKey> TreeKey for Range<T>

source§

fn traverse_all<W: Walk>() -> Result<W, W::Error>

source§

fn traverse_by_key<K, F, G>(keys: K, func: F) -> Result<usize, Error<G>>
where K: Keys, F: FnMut(usize, Option<&'static str>, NonZero<usize>) -> Result<(), G>,

source§

impl<T: TreeKey> TreeKey for RangeFrom<T>

source§

fn traverse_all<W: Walk>() -> Result<W, W::Error>

source§

fn traverse_by_key<K, F, G>(keys: K, func: F) -> Result<usize, Error<G>>
where K: Keys, F: FnMut(usize, Option<&'static str>, NonZero<usize>) -> Result<(), G>,

source§

impl<T: TreeKey> TreeKey for RangeInclusive<T>

source§

fn traverse_all<W: Walk>() -> Result<W, W::Error>

source§

fn traverse_by_key<K, F, G>(keys: K, func: F) -> Result<usize, Error<G>>
where K: Keys, F: FnMut(usize, Option<&'static str>, NonZero<usize>) -> Result<(), G>,

source§

impl<T: TreeKey> TreeKey for RangeTo<T>

source§

fn traverse_all<W: Walk>() -> Result<W, W::Error>

source§

fn traverse_by_key<K, F, G>(keys: K, func: F) -> Result<usize, Error<G>>
where K: Keys, F: FnMut(usize, Option<&'static str>, NonZero<usize>) -> Result<(), G>,

source§

impl<T: TreeKey, E: TreeKey> TreeKey for Result<T, E>

source§

fn traverse_all<W: Walk>() -> Result<W, W::Error>

source§

fn traverse_by_key<K, F, G>(keys: K, func: F) -> Result<usize, Error<G>>
where K: Keys, F: FnMut(usize, Option<&'static str>, NonZero<usize>) -> Result<(), G>,

source§

impl<T: TreeKey, const N: usize> TreeKey for [T; N]

source§

fn traverse_all<W: Walk>() -> Result<W, W::Error>

source§

fn traverse_by_key<K, F, E>(keys: K, func: F) -> Result<usize, Error<E>>
where K: Keys, F: FnMut(usize, Option<&'static str>, NonZero<usize>) -> Result<(), E>,

Implementors§

source§

impl<T: ?Sized> TreeKey for Deny<T>

source§

impl<T: ?Sized> TreeKey for Leaf<T>

source§

impl<T: ?Sized> TreeKey for StrLeaf<T>