1use std::fmt;
16use std::fmt::Display;
17
18#[derive(Clone, Debug, Default)]
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
54pub enum PathType {
55 RecordPath(Path),
56 IndexPath(Path),
57}
58
59impl PathType {
60 pub fn from_path(path: &Path) -> Option<PathType> {
61 if path.0.first().map(|elem| elem.is_field()).unwrap_or(false) {
62 Some(PathType::RecordPath(path.clone()))
63 } else if path.0.first().map(|elem| elem.is_index()).unwrap_or(false) {
64 Some(PathType::IndexPath(path.clone()))
65 } else {
66 None
67 }
68 }
69}
70
71impl Display for Path {
72 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73 let mut is_first = true;
74
75 for elem in &self.0 {
76 match elem {
77 PathElem::Field(name) => {
78 if is_first {
79 write!(f, "{}", name)?;
80 is_first = false;
81 } else {
82 write!(f, ".{}", name)?;
83 }
84 }
85 PathElem::Index(index) => {
86 if is_first {
87 write!(f, "index: {}", index)?;
88 is_first = false;
89 } else {
90 write!(f, "[{}]", index)?;
91 }
92 }
93 }
94 }
95 Ok(())
96 }
97}
98
99#[derive(Clone, Debug, PartialEq)]
100pub enum PathElem {
101 Field(String),
102 Index(usize),
103}
104
105impl PathElem {
106 pub fn is_field(&self) -> bool {
107 matches!(self, PathElem::Field(_))
108 }
109
110 pub fn is_index(&self) -> bool {
111 matches!(self, PathElem::Index(_))
112 }
113}