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/variant through TreeKey/TreeDeserialize::probe can be overridden using the typ derive macro attribute (#[tree(typ="[f32; 4]")]).

§Deny

#[tree(deny(operation="message", ...))]

This returns Err(Traversal::Access) for the respective operation (traverse, serialize, deserialize, probe, ref_any, mut_any) on a field/variant and suppresses the respective traits bounds on type paramters of the struct/enum.

§Implementation overrides

#[tree(with(operation=expr, ...))]

This overrides the call to the child node/variant trait for the given operation (traverse, traverse_all, serialize, deserialize, probe, ref_any, mut_any). expr should be a method on self (not the field!) or value (associated function for traverse, traverse_all and probe) taking the arguments of the respective trait’s method.

#[derive(Tree, Default)]
struct S {
    #[tree(with(deserialize=self.check))]
    b: Leaf<f32>,
};
impl S {
    fn check<'de, K: Keys, D: Deserializer<'de>>(&mut self, keys: K, de: D) -> Result<(), Error<D::Error>> {
        let old = *self.b;
        self.b.deserialize_by_key(keys, de)?;
        if *self.b < 0.0 {
            *self.b = old;
            Err(Traversal::Access(0, "fail").into())
        } else {
            Ok(())
        }
    }
}

§defer

The defer attribute is a shorthand for with() that defers child trait implementations to a given expression.

§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.

This method should fail if and only if the key is invalid. It should succeed at least when any of the other key based methods in TreeAny, TreeSerialize, and TreeDeserialize succeed.

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

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety", so 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>