substrait_validator/output/
path.rs1use crate::util;
12
13#[derive(Clone, Debug, PartialEq, Eq)]
15pub enum PathElement {
16 Field(String),
19
20 Repeated(String, usize),
23
24 Variant(String, String),
28
29 Index(usize),
31}
32
33impl std::fmt::Display for PathElement {
34 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35 if !f.alternate() {
36 match self {
37 PathElement::Index(_) => {}
38 _ => write!(f, ".")?,
39 }
40 }
41 match self {
42 PathElement::Field(field) => write!(f, "{}", util::string::as_ident_or_string(field)),
43 PathElement::Repeated(field, index) => {
44 write!(f, "{}[{index}]", util::string::as_ident_or_string(field))
45 }
46 PathElement::Variant(field, variant) => write!(
47 f,
48 "{}<{}>",
49 util::string::as_ident_or_string(field),
50 util::string::as_ident_or_string(variant)
51 ),
52 PathElement::Index(index) => write!(f, "[{index}]"),
53 }
54 }
55}
56
57impl PathElement {
58 pub fn to_string_without_dot(&self) -> String {
61 format!("{:#}", self)
62 }
63}
64
65#[derive(Clone, Debug, PartialEq, Eq)]
67pub struct PathBuf {
68 pub root: &'static str,
69 pub elements: Vec<PathElement>,
70}
71
72impl std::fmt::Display for PathBuf {
73 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
74 write!(f, "{}", self.root)?;
75 for element in self.elements.iter() {
76 write!(f, "{element}")?;
77 }
78 Ok(())
79 }
80}
81
82#[derive(Clone, Debug, PartialEq)]
85pub enum Path<'a> {
86 Root(&'static str),
88
89 Select(&'a Path<'a>, PathElement),
92}
93
94impl Default for Path<'_> {
95 fn default() -> Self {
96 Path::Root("")
97 }
98}
99
100impl Path<'_> {
101 pub fn with(&self, element: PathElement) -> Path {
105 Path::Select(self, element)
106 }
107
108 pub fn with_field<S: Into<String>>(&self, name: S) -> Path {
112 self.with(PathElement::Field(name.into()))
113 }
114
115 pub fn with_repeated<S: Into<String>>(&self, name: S, index: usize) -> Path {
119 self.with(PathElement::Repeated(name.into(), index))
120 }
121
122 pub fn with_variant<S: Into<String>, V: Into<String>>(&self, name: S, variant: V) -> Path {
126 self.with(PathElement::Variant(name.into(), variant.into()))
127 }
128
129 pub fn with_index(&self, index: usize) -> Path {
131 self.with(PathElement::Index(index))
132 }
133}
134
135impl std::fmt::Display for Path<'_> {
136 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
137 match self {
138 Path::Root(name) => write!(f, "{name}"),
139 Path::Select(parent, element) => write!(f, "{parent}{element}"),
140 }
141 }
142}
143
144impl Path<'_> {
145 pub fn end_to_string(&self) -> String {
146 match self {
147 Path::Root(name) => name.to_string(),
148 Path::Select(_, element) => element.to_string(),
149 }
150 }
151
152 pub fn to_path_buf(&self) -> PathBuf {
154 match self {
155 Path::Root(name) => PathBuf {
156 root: name,
157 elements: vec![],
158 },
159 Path::Select(parent, element) => {
160 let mut parent = parent.to_path_buf();
161 parent.elements.push(element.clone());
162 parent
163 }
164 }
165 }
166}
167
168impl From<Path<'_>> for PathBuf {
169 fn from(path: Path<'_>) -> Self {
170 path.to_path_buf()
171 }
172}
173
174#[cfg(test)]
175mod tests {
176 use super::*;
177
178 #[test]
179 fn paths() {
180 let a = Path::Root("a");
181 let b = a.with_field("b");
182 let c = b.with_repeated("c", 42);
183 let d = c.with_variant("d", "e");
184 let e = d.with_index(33);
185 let buf: PathBuf = e.to_path_buf();
186 assert_eq!(e.to_string(), "a.b.c[42].d<e>[33]");
187 assert_eq!(buf.to_string(), "a.b.c[42].d<e>[33]");
188 }
189
190 #[test]
191 fn non_ident_paths() {
192 let a = Path::Root("a");
193 let b = a.with_field("4");
194 let c = b.with_repeated("8", 15);
195 let d = c.with_variant("16", "23");
196 let e = d.with_index(42);
197 let buf: PathBuf = e.to_path_buf();
198 assert_eq!(e.to_string(), "a.\"4\".\"8\"[15].\"16\"<\"23\">[42]");
199 assert_eq!(buf.to_string(), "a.\"4\".\"8\"[15].\"16\"<\"23\">[42]");
200 }
201}