1use core::fmt;
4
5use crate::{Failure, DEPTH};
6
7impl fmt::Display for Failure {
8 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
10 expand(self.path, &self.at, f).map_err(|()| fmt::Error)
11 }
12}
13
14trait Sink {
17 fn text(&mut self, s: &str) -> Result<(), ()>;
19 fn hole(&mut self, entry: u32) -> Result<(), ()>;
21}
22
23impl Sink for fmt::Formatter<'_> {
24 fn text(&mut self, s: &str) -> Result<(), ()> {
25 self.write_str(s).map_err(drop)
26 }
27
28 fn hole(&mut self, entry: u32) -> Result<(), ()> {
29 write!(self, "[{entry}]").map_err(drop)
30 }
31}
32
33#[derive(Clone, Copy, Debug, Default)]
35pub struct Trail {
36 at: [u32; DEPTH],
37 len: usize,
38}
39
40impl Trail {
41 pub const fn new() -> Trail {
42 Trail {
43 at: [0; DEPTH],
44 len: 0,
45 }
46 }
47
48 pub fn push(mut self, entry: u32) -> Trail {
49 if let Some(slot) = self.at.get_mut(self.len) {
50 *slot = entry;
51 self.len = self.len.saturating_add(1);
52 }
53 self
54 }
55
56 pub fn join(self, other: &Trail) -> Trail {
58 other.as_slice().iter().fold(self, |t, e| t.push(*e))
59 }
60
61 pub fn as_slice(&self) -> &[u32] {
62 self.at.get(..self.len).unwrap_or_default()
63 }
64}
65
66fn expand(path: &str, at: &[u32], w: &mut impl Sink) -> Result<(), ()> {
68 let mut next = at.iter().copied();
69 let mut rest = path;
70 while !rest.is_empty() {
71 let (head, mark, tail) =
72 match cut(rest, "(").and_then(|(h, a)| cut(a, ")*").map(|(m, t)| (h, m, t))) {
73 Some((head, mark, tail)) => (head, Some(mark), tail),
74 None => (rest, None, ""),
75 };
76 holes(head, &mut next, w)?;
77 if let Some(steps) = mark {
78 repeat(steps, &mut next, w)?;
79 }
80 rest = tail;
81 }
82 Ok(())
83}
84
85fn repeat(steps: &str, next: &mut impl Iterator<Item = u32>, w: &mut impl Sink) -> Result<(), ()> {
88 let several = cut(steps, "|").is_some();
89 for _ in 0..next.next().unwrap_or(0) {
90 let pick = if several { next.next().unwrap_or(0) } else { 0 };
91 let step = Split::new(steps, "|")
92 .nth(pick as usize)
93 .unwrap_or_default();
94 holes(step, next, w)?;
95 }
96 Ok(())
97}
98
99fn holes(text: &str, next: &mut impl Iterator<Item = u32>, w: &mut impl Sink) -> Result<(), ()> {
101 let mut parts = Split::new(text, "[]");
102 w.text(parts.next().unwrap_or_default())?;
103 for part in parts {
104 w.hole(next.next().unwrap_or(0))?;
105 w.text(part)?;
106 }
107 Ok(())
108}
109
110fn cut<'s>(s: &'s str, pat: &str) -> Option<(&'s str, &'s str)> {
113 let at = s
114 .as_bytes()
115 .windows(pat.len().max(1))
116 .position(|w| w == pat.as_bytes())?;
117 Some((s.get(..at)?, s.get(at.checked_add(pat.len())?..)?))
118}
119
120struct Split<'s> {
122 rest: Option<&'s str>,
123 pat: &'static str,
124}
125
126impl<'s> Split<'s> {
127 fn new(s: &'s str, pat: &'static str) -> Split<'s> {
128 Split { rest: Some(s), pat }
129 }
130}
131
132impl<'s> Iterator for Split<'s> {
133 type Item = &'s str;
134
135 fn next(&mut self) -> Option<&'s str> {
136 let s = self.rest?;
137 let (part, rest) = cut(s, self.pat).map_or((s, None), |(h, t)| (h, Some(t)));
138 self.rest = rest;
139 Some(part)
140 }
141}
142
143pub fn under(path: &str, failed: &str, at: &[u32]) -> bool {
146 let mut prefix = Prefix {
147 want: path.as_bytes(),
148 seen: 0,
149 ok: true,
150 };
151 let _ = expand(failed, at, &mut prefix);
152 prefix.ok && prefix.seen >= path.len()
153}
154
155struct Prefix<'a> {
157 want: &'a [u8],
158 seen: usize,
159 ok: bool,
160}
161
162impl Sink for Prefix<'_> {
163 fn text(&mut self, s: &str) -> Result<(), ()> {
164 for b in s.bytes() {
165 match self.want.get(self.seen) {
166 Some(w) if *w == b => {}
167 Some(_) => self.ok = false,
168 None => self.ok = b == b'.' || b == b'[',
169 }
170 if !self.ok || self.seen >= self.want.len() {
171 return Err(());
172 }
173 self.seen = self.seen.saturating_add(1);
174 }
175 Ok(())
176 }
177
178 fn hole(&mut self, _: u32) -> Result<(), ()> {
180 self.text("[]")
181 }
182}
183
184#[cfg(test)]
185mod tests {
186 extern crate std;
187 use std::string::ToString;
188
189 use crate::{Failures, Reason, Report};
190
191 use super::*;
192
193 fn failure(path: &'static str, at: &[u32]) -> Failure {
194 let mut f = Failures::<1>::default();
195 f.fail(path, at, Reason::Range);
196 let kept = *f.iter().next().unwrap();
197 kept
198 }
199
200 #[test]
201 fn marks_expand_by_their_count_and_indices() {
202 let chain = failure("Value(.next)*.n", &[2]);
203 assert_eq!(chain.to_string(), "Value.next.next.n");
204 assert_eq!(failure("Value(.next)*.n", &[0]).to_string(), "Value.n");
205 let tree = failure("Value.root(.children[])*.leaf[]", &[2, 4, 1, 7]);
206 assert_eq!(
207 tree.to_string(),
208 "Value.root.children[4].children[1].leaf[7]"
209 );
210 let past = failure("Value(.c[])*.leaf", &[5, 1, 1, 1, 1, 1]);
211 assert_eq!(past.to_string(), "Value.c[1].c[1].c[1].c[0].c[0].leaf");
212 }
213
214 #[test]
215 fn alternating_marks_read_a_step_index_per_repeat() {
216 let tree = failure("Value(.left|.right)*.n", &[3, 0, 1, 1]);
217 assert_eq!(tree.to_string(), "Value.left.right.right.n");
218 let mixed = failure("Value(.kids[]|.next)*.n", &[2, 0, 2, 1]);
219 assert_eq!(mixed.to_string(), "Value.kids[2].next.n");
220 assert_eq!(failure("Value(.l|.r)*.n", &[0]).to_string(), "Value.n");
221 let past = failure("Value(.l|.r)*.n", &[3, 1, 1, 1]);
222 assert_eq!(past.to_string(), "Value.r.r.r.n");
223 let cut = failure("Value(.l|.r)*.n", &[3, 1, 1, 1, 1, 1]);
224 assert_eq!(cut.to_string(), "Value.r.r.r.n");
225 }
226
227 #[test]
228 fn under_reads_alternating_marks() {
229 assert!(under("V.left.right", "V(.left|.right)*.n", &[2, 0, 1]));
230 assert!(!under("V.left.left", "V(.left|.right)*.n", &[2, 0, 1]));
231 assert!(under("V.kids[].next", "V(.kids[]|.next)*.n", &[2, 0, 4, 1]));
232 assert!(under("V.n", "V(.left|.right)*.n", &[0]));
233 }
234
235 #[test]
236 fn split_parts_as_str_split_does() {
237 use std::vec::Vec;
238 for text in ["", "[]", "a[]", "[]b", "a[]b[][]c", "a[b]", "é[]ü[", "[[]]"] {
239 let ours: Vec<_> = Split::new(text, "[]").collect();
240 assert_eq!(ours, text.split("[]").collect::<Vec<_>>(), "{text}");
241 }
242 assert_eq!(cut("a)*b)*", ")*"), Some(("a", "b)*")));
243 assert_eq!(cut("a)", ")*"), None);
244 assert_eq!(cut("abc", ""), None);
245 }
246
247 #[test]
248 fn a_trail_keeps_its_first_entries() {
249 let rest = Trail::new().push(2).push(3);
250 let t = Trail::new().push(1).join(&rest).push(4).push(5);
251 assert_eq!(t.as_slice(), &[1, 2, 3, 4]);
252 }
253
254 #[test]
255 fn under_reads_marks_as_expanded() {
256 assert!(under("V.next", "V(.next)*.n", &[1]));
257 assert!(under("V.next.next", "V(.next)*.n", &[2]));
258 assert!(!under("V.next", "V(.next)*.n", &[0]));
259 assert!(under("V.n", "V(.next)*.n", &[0]));
260 assert!(under("V.c[]", "V(.c[])*.n", &[1, 3]));
261 }
262}