Skip to main content

facet_diff_core/
path.rs

1//! Path types for navigating diff trees.
2
3use std::borrow::Cow;
4
5/// A path segment describing how to reach a child.
6#[derive(Debug, Clone, PartialEq, Eq, Hash, facet::Facet)]
7#[repr(u8)]
8pub enum PathSegment {
9    /// A named field in a struct
10    Field(Cow<'static, str>),
11    /// An index in a list/array
12    Index(usize),
13    /// A key in a map
14    Key(Cow<'static, str>),
15    /// An enum variant
16    Variant(Cow<'static, str>),
17}
18
19/// A path from root to a node.
20#[derive(Debug, Clone, PartialEq, Eq, Default, Hash, facet::Facet)]
21pub struct Path(pub Vec<PathSegment>);
22
23impl Path {
24    /// Create a new empty path.
25    pub const fn new() -> Self {
26        Self(Vec::new())
27    }
28
29    /// Append a segment to this path.
30    pub fn push(&mut self, segment: PathSegment) {
31        self.0.push(segment);
32    }
33
34    /// Create a new path with an additional segment.
35    pub fn with(&self, segment: PathSegment) -> Self {
36        let mut new = self.clone();
37        new.push(segment);
38        new
39    }
40}
41
42impl core::fmt::Display for Path {
43    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
44        for (i, segment) in self.0.iter().enumerate() {
45            match segment {
46                PathSegment::Field(name) => {
47                    if i > 0 {
48                        write!(f, ".")?;
49                    }
50                    write!(f, "{}", name)?;
51                }
52                PathSegment::Index(idx) => {
53                    if i > 0 {
54                        write!(f, ".")?;
55                    }
56                    write!(f, "{}", idx)?;
57                }
58                PathSegment::Key(key) => write!(f, "[{:?}]", key)?,
59                PathSegment::Variant(name) => write!(f, "::{}", name)?,
60            }
61        }
62        Ok(())
63    }
64}