Skip to main content

statime_config/tree/
path.rs

1//! Paths into the configuration tree, used to point at a setting in
2//! diagnostics.
3
4/// A segment of a path in the tree. Field names are static schema data, while
5/// vector indexes are only known while walking a document.
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7enum PathSegment {
8    Field(&'static str),
9    Index(usize),
10}
11
12/// A path in the tree, such as `observability.log-level` or
13/// `sources[2].address`.
14#[derive(Debug, Clone, PartialEq, Eq)]
15pub struct ConfigPath(Vec<PathSegment>);
16
17impl ConfigPath {
18    pub fn root() -> Self {
19        Self(vec![])
20    }
21
22    /// Run `f` with `field` appended to this path.
23    pub fn at<R>(&mut self, field: &'static str, f: impl FnOnce(&mut Self) -> R) -> R {
24        self.push_field(field);
25        let result = f(self);
26        self.pop();
27        result
28    }
29
30    /// Run `f` with an element of a vector appended to this path.
31    pub(crate) fn at_index<R>(&mut self, index: usize, f: impl FnOnce(&mut Self) -> R) -> R {
32        self.0.push(PathSegment::Index(index));
33        let result = f(self);
34        self.pop();
35        result
36    }
37
38    pub(crate) fn push_field(&mut self, field: &'static str) {
39        self.0.push(PathSegment::Field(field));
40    }
41
42    pub(crate) fn pop(&mut self) {
43        self.0.pop();
44    }
45}
46
47impl std::fmt::Display for ConfigPath {
48    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
49        for (pos, segment) in self.0.iter().enumerate() {
50            match segment {
51                PathSegment::Field(field) => {
52                    if pos != 0 {
53                        write!(f, ".")?;
54                    }
55                    write!(f, "{field}")?
56                }
57                PathSegment::Index(index) => write!(f, "[{index}]")?,
58            }
59        }
60
61        Ok(())
62    }
63}