1use std::fmt;
2use std::fmt::Display;
3
4#[derive(Clone, Debug, Default, PartialEq)]
5pub struct Path(Vec<PathElem>);
6
7impl Path {
8 pub fn is_empty(&self) -> bool {
9 self.0.is_empty()
10 }
11
12 pub fn current(&self) -> Option<&PathElem> {
13 self.0.first()
14 }
15
16 pub fn progress(&mut self) {
17 if !self.0.is_empty() {
18 self.0.remove(0);
19 }
20 }
21
22 pub fn from_elem(elem: PathElem) -> Self {
23 Path(vec![elem])
24 }
25
26 pub fn from_elems(elems: Vec<&str>) -> Self {
27 Path(
28 elems
29 .iter()
30 .map(|x| PathElem::Field(x.to_string()))
31 .collect(),
32 )
33 }
34
35 pub fn push_front(&mut self, elem: PathElem) {
36 self.0.insert(0, elem);
37 }
38
39 pub fn push_back(&mut self, elem: PathElem) {
40 self.0.push(elem);
41 }
42}
43
44pub enum PathType {
45 RecordPath(Path),
46 IndexPath(Path),
47}
48
49impl PathType {
50 pub fn from_path(path: &Path) -> Option<PathType> {
51 if path.0.first().map(|elem| elem.is_field()).unwrap_or(false) {
52 Some(PathType::RecordPath(path.clone()))
53 } else if path.0.first().map(|elem| elem.is_index()).unwrap_or(false) {
54 Some(PathType::IndexPath(path.clone()))
55 } else {
56 None
57 }
58 }
59}
60
61impl Display for Path {
62 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
63 let mut is_first = true;
64
65 for elem in &self.0 {
66 match elem {
67 PathElem::Field(name) => {
68 if is_first {
69 write!(f, "{name}")?;
70 is_first = false;
71 } else {
72 write!(f, ".{name}")?;
73 }
74 }
75 PathElem::Index(index) => {
76 if is_first {
77 write!(f, "index: {index}")?;
78 is_first = false;
79 } else {
80 write!(f, "[{index}]")?;
81 }
82 }
83 }
84 }
85 Ok(())
86 }
87}
88
89#[derive(Clone, Debug, PartialEq)]
90pub enum PathElem {
91 Field(String),
92 Index(usize),
93}
94
95impl PathElem {
96 pub fn is_field(&self) -> bool {
97 matches!(self, PathElem::Field(_))
98 }
99
100 pub fn is_index(&self) -> bool {
101 matches!(self, PathElem::Index(_))
102 }
103}