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