path_tree/
node.rs

1use alloc::{string::String, vec::Vec};
2use core::{
3    cmp::Ordering,
4    fmt::{self, Write},
5    ops::Range,
6};
7
8use smallvec::SmallVec;
9
10use crate::Kind;
11
12#[derive(Clone, Debug, PartialEq, Eq)]
13pub enum Key {
14    String(Vec<u8>),
15    Parameter(Kind),
16}
17
18#[derive(Clone)]
19pub struct Node<T> {
20    pub key: Key,
21    pub value: Option<T>,
22    /// Stores string node
23    pub nodes0: Option<Vec<Self>>,
24    /// Stores parameter node
25    pub nodes1: Option<Vec<Self>>,
26}
27
28impl<T: fmt::Debug> Node<T> {
29    pub fn new(key: Key, value: Option<T>) -> Self {
30        Self {
31            key,
32            value,
33            nodes0: None,
34            nodes1: None,
35        }
36    }
37
38    pub fn insert_bytes(&mut self, mut bytes: &[u8]) -> &mut Self {
39        let diff = match &mut self.key {
40            Key::String(s) => {
41                if s.is_empty() {
42                    *s = bytes.to_vec();
43                    return self;
44                }
45
46                let cursor = s
47                    .iter()
48                    .zip(bytes.iter())
49                    .take_while(|(a, b)| a == b)
50                    .count();
51
52                if cursor == 0 {
53                    true
54                } else {
55                    // split node
56                    if cursor < s.len() {
57                        let (prefix, suffix) = s.split_at(cursor);
58                        let mut node = Node::new(Key::String(prefix.to_vec()), None);
59                        *s = suffix.to_vec();
60                        ::core::mem::swap(self, &mut node);
61                        self.nodes0.get_or_insert_with(Vec::new).push(node);
62                    }
63                    if cursor == bytes.len() {
64                        false
65                    } else {
66                        bytes = &bytes[cursor..];
67                        true
68                    }
69                }
70            }
71            Key::Parameter(_) => true,
72        };
73
74        // insert node
75        if diff {
76            let nodes = self.nodes0.get_or_insert_with(Vec::new);
77            return match nodes.binary_search_by(|node| match &node.key {
78                Key::String(s) => {
79                    // s[0].cmp(&bytes[0])
80                    // opt!
81                    // lets `/` at end
82                    compare(s[0], bytes[0])
83                }
84                Key::Parameter(_) => unreachable!(),
85            }) {
86                Ok(i) => nodes[i].insert_bytes(bytes),
87                Err(i) => {
88                    nodes.insert(i, Node::new(Key::String(bytes.to_vec()), None));
89                    &mut nodes[i]
90                }
91            };
92        }
93
94        self
95    }
96
97    pub fn insert_parameter(&mut self, kind: Kind) -> &mut Self {
98        let nodes = self.nodes1.get_or_insert_with(Vec::new);
99        let i = nodes
100            .binary_search_by(|node| match node.key {
101                Key::Parameter(pk) => pk.cmp(&kind),
102                Key::String(_) => unreachable!(),
103            })
104            .unwrap_or_else(|i| {
105                nodes.insert(i, Node::new(Key::Parameter(kind), None));
106                i
107            });
108        &mut nodes[i]
109    }
110
111    #[allow(clippy::range_plus_one)]
112    #[allow(clippy::too_many_lines)]
113    #[inline]
114    fn find_with(
115        &self,
116        mut start: usize,
117        mut bytes: &[u8],
118        ranges: &mut SmallVec<[Range<usize>; 8]>,
119    ) -> Option<&T> {
120        let mut m = bytes.len();
121        match &self.key {
122            Key::String(s) => {
123                let n = s.len();
124                let mut flag = m >= n;
125
126                // opt!
127                if flag {
128                    if n == 1 {
129                        flag = s[0] == bytes[0];
130                    } else {
131                        flag = s == &bytes[..n];
132                    }
133                }
134
135                // starts with prefix
136                if flag {
137                    m -= n;
138                    start += n;
139                    bytes = &bytes[n..];
140
141                    if m == 0 {
142                        if let Some(id) = &self.value {
143                            return Some(id);
144                        }
145                    } else {
146                        // static
147                        if let Some(id) = self.nodes0.as_ref().and_then(|nodes| {
148                            nodes
149                                .binary_search_by(|node| match &node.key {
150                                    Key::String(s) => {
151                                        // s[0].cmp(&bytes[0])
152                                        // opt!
153                                        // lets `/` at end
154                                        compare(s[0], bytes[0])
155                                    }
156                                    Key::Parameter(_) => unreachable!(),
157                                })
158                                .ok()
159                                .and_then(|i| nodes[i].find_with(start, bytes, ranges))
160                        }) {
161                            return Some(id);
162                        }
163                    }
164
165                    // parameter
166                    if let Some(id) = self.nodes1.as_ref().and_then(|nodes| {
167                        let b = m > 0;
168                        nodes
169                            .iter()
170                            .filter(|node| match node.key {
171                                Key::Parameter(pk)
172                                    if pk == Kind::Normal || pk == Kind::OneOrMore =>
173                                {
174                                    b
175                                }
176                                _ => true,
177                            })
178                            .find_map(|node| node.find_with(start, bytes, ranges))
179                    }) {
180                        return Some(id);
181                    }
182                } else if n == 1 && s[0] == b'/' {
183                    if let Some(id) = self.nodes1.as_ref().and_then(|nodes| {
184                        nodes
185                            .iter()
186                            .filter(|node| {
187                                matches!(node.key,
188                                    Key::Parameter(pk)
189                                        if pk == Kind::OptionalSegment
190                                            || pk == Kind::ZeroOrMoreSegment
191                                )
192                            })
193                            .find_map(|node| node.find_with(start, bytes, ranges))
194                    }) {
195                        return Some(id);
196                    }
197                }
198            }
199            Key::Parameter(k) => match k {
200                Kind::Normal | Kind::Optional | Kind::OptionalSegment => {
201                    if m == 0 {
202                        if k == &Kind::Normal {
203                            return None;
204                        }
205
206                        // last
207                        if self.nodes0.is_none() && self.nodes1.is_none() {
208                            return self.value.as_ref().inspect(|_| {
209                                ranges.push(start..start);
210                            });
211                        }
212                    } else {
213                        // static
214                        if let Some(id) = self.nodes0.as_ref().and_then(|nodes| {
215                            nodes.iter().find_map(|node| match &node.key {
216                                Key::String(s) => {
217                                    let mut keep_running = true;
218                                    bytes
219                                        .iter()
220                                        // as it turns out doing .copied() here is much slower than dereferencing in the closure
221                                        // https://godbolt.org/z/7dnW91T1Y
222                                        .take_while(|b| {
223                                            if keep_running && **b == b'/' {
224                                                keep_running = false;
225                                                true
226                                            } else {
227                                                keep_running
228                                            }
229                                        })
230                                        .enumerate()
231                                        .filter_map(|(n, b)| (s[0] == *b).then_some(n))
232                                        .find_map(|n| {
233                                            node.find_with(start + n, &bytes[n..], ranges).inspect(
234                                                |_| {
235                                                    ranges.push(start..start + n);
236                                                },
237                                            )
238                                        })
239                                }
240                                Key::Parameter(_) => unreachable!(),
241                            })
242                        }) {
243                            return Some(id);
244                        }
245
246                        // parameter => `:a:b:c`
247                        if let Some(id) = self.nodes1.as_ref().and_then(|nodes| {
248                            let b = m - 1 > 0;
249                            nodes
250                                .iter()
251                                .filter(|node| match node.key {
252                                    Key::Parameter(pk)
253                                        if pk == Kind::Normal || pk == Kind::OneOrMore =>
254                                    {
255                                        b
256                                    }
257                                    _ => true,
258                                })
259                                .find_map(|node| node.find_with(start + 1, &bytes[1..], ranges))
260                        }) {
261                            ranges.push(start..start + 1);
262                            return Some(id);
263                        }
264                    }
265
266                    // parameter => `:a:b?:c?`
267                    if k == &Kind::Optional || k == &Kind::OptionalSegment {
268                        if let Some(id) = self.nodes1.as_ref().and_then(|nodes| {
269                            let b = m > 0;
270                            nodes
271                                .iter()
272                                .filter(|node| match &node.key {
273                                    Key::Parameter(pk)
274                                        if pk == &Kind::Normal || pk == &Kind::OneOrMore =>
275                                    {
276                                        b
277                                    }
278                                    _ => true,
279                                })
280                                .find_map(|node| node.find_with(start, bytes, ranges))
281                        }) {
282                            // param should be empty
283                            ranges.push(start + m..start + m);
284                            return Some(id);
285                        }
286                    }
287
288                    if let Some(n) = bytes.iter().position(|b| *b == b'/') {
289                        bytes = &bytes[n..];
290                    } else {
291                        if let Some(id) = &self.value {
292                            ranges.push(start..start + m);
293                            return Some(id);
294                        }
295                        bytes = &bytes[m..];
296                    }
297
298                    if k == &Kind::OptionalSegment {
299                        if let Some(id) = self.nodes0.as_ref().and_then(|nodes| {
300                            nodes
301                                .last()
302                                .filter(|node| match &node.key {
303                                    Key::String(s) => s[0] == b'/',
304                                    Key::Parameter(_) => unreachable!(),
305                                })
306                                .and_then(|node| node.find_with(start, bytes, ranges))
307                        }) {
308                            ranges.push(start..start + m);
309                            return Some(id);
310                        }
311                    }
312                }
313                Kind::OneOrMore | Kind::ZeroOrMore | Kind::ZeroOrMoreSegment => {
314                    let is_one_or_more = k == &Kind::OneOrMore;
315                    if m == 0 {
316                        if is_one_or_more {
317                            return None;
318                        }
319
320                        if self.nodes0.is_none() && self.nodes1.is_none() {
321                            return self.value.as_ref().inspect(|_| {
322                                ranges.push(start..start);
323                            });
324                        }
325                    } else {
326                        if self.nodes0.is_none() && self.nodes1.is_none() {
327                            if let Some(id) = &self.value {
328                                ranges.push(start..start + m);
329                                return Some(id);
330                            }
331                        }
332
333                        // static
334                        if let Some(id) = self.nodes0.as_ref().and_then(|nodes| {
335                            nodes.iter().find_map(|node| {
336                                if let Key::String(s) = &node.key {
337                                    let right_length = if is_one_or_more {
338                                        m > s.len()
339                                    } else {
340                                        m >= s.len()
341                                    };
342                                    if right_length {
343                                        return bytes
344                                            .iter()
345                                            .enumerate()
346                                            .filter_map(|(n, b)| (s[0] == *b).then_some(n))
347                                            .find_map(|n| {
348                                                node.find_with(start + n, &bytes[n..], ranges)
349                                                    .inspect(|_| {
350                                                        ranges.push(start..start + n);
351                                                    })
352                                            });
353                                    }
354                                }
355                                None
356                            })
357                        }) {
358                            return Some(id);
359                        }
360                    }
361
362                    if k == &Kind::ZeroOrMoreSegment {
363                        if let Some(id) = self.nodes0.as_ref().and_then(|nodes| {
364                            nodes
365                                .last()
366                                .filter(|node| match &node.key {
367                                    Key::String(s) => s[0] == b'/',
368                                    Key::Parameter(_) => unreachable!(),
369                                })
370                                .and_then(|node| node.find_with(start, bytes, ranges))
371                        }) {
372                            // param should be empty
373                            ranges.push(start + m..start + m);
374                            return Some(id);
375                        }
376                    }
377                }
378            },
379        }
380        None
381    }
382
383    pub fn find(&self, bytes: &[u8]) -> Option<(&T, SmallVec<[Range<usize>; 8]>)> {
384        let mut ranges = SmallVec::<[Range<usize>; 8]>::new_const(); // opt!
385        self.find_with(0, bytes, &mut ranges).map(|t| (t, ranges))
386    }
387}
388
389impl<T: fmt::Debug> fmt::Debug for Node<T> {
390    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
391        const EDGE: &str = "├──";
392        const LINE: &str = "│  ";
393        const CORNER: &str = "└──";
394        const BLANK: &str = "   ";
395
396        fn print_nodes<T: fmt::Debug>(
397            f: &mut fmt::Formatter<'_>,
398            nodes: &[Node<T>],
399            check: bool,
400            pad: &str,
401            space: &str,
402        ) -> fmt::Result {
403            for (index, node) in nodes.iter().enumerate() {
404                let (left, right) = if check && index == nodes.len() - 1 {
405                    (BLANK, CORNER)
406                } else {
407                    (LINE, EDGE)
408                };
409                f.write_str(pad)?;
410                f.write_str(space)?;
411                f.write_str(right)?;
412                let mut s = String::new();
413                s.push_str(pad);
414                s.push_str(space);
415                s.push_str(left);
416                print_tree(f, node, false, &s)?;
417            }
418            Ok(())
419        }
420
421        fn print_tree<T: fmt::Debug>(
422            f: &mut fmt::Formatter<'_>,
423            node: &Node<T>,
424            root: bool,
425            pad: &str,
426        ) -> fmt::Result {
427            let space = if root {
428                f.write_char('\n')?;
429                ""
430            } else {
431                f.write_char(' ')?;
432                " "
433            };
434            match &node.key {
435                Key::String(path) => {
436                    f.write_str(
437                        &String::from_utf8_lossy(path)
438                            .replace(':', "\\:")
439                            .replace('?', "\\?")
440                            .replace('+', "\\+"),
441                    )?;
442                }
443                Key::Parameter(kind) => {
444                    let c = match kind {
445                        Kind::Normal => ':',
446                        Kind::Optional => '?',
447                        Kind::OptionalSegment => {
448                            f.write_char('?')?;
449                            '?'
450                        }
451                        Kind::OneOrMore => '+',
452                        Kind::ZeroOrMore => '*',
453                        Kind::ZeroOrMoreSegment => {
454                            f.write_char('*')?;
455                            '*'
456                        }
457                    };
458                    f.write_char(c)?;
459                }
460            }
461            if let Some(value) = &node.value {
462                f.write_str(" •")?;
463                value.fmt(f)?;
464            }
465            f.write_char('\n')?;
466
467            // nodes0
468            if let Some(nodes) = &node.nodes0 {
469                print_nodes(f, nodes, node.nodes1.is_none(), pad, space)?;
470            }
471
472            // nodes1
473            if let Some(nodes) = &node.nodes1 {
474                print_nodes(f, nodes, true, pad, space)?;
475            }
476
477            Ok(())
478        }
479
480        print_tree(f, self, true, "")
481    }
482}
483
484#[inline]
485fn compare(a: u8, b: u8) -> Ordering {
486    if a == b {
487        Ordering::Equal
488    } else if a == b'/' {
489        Ordering::Greater
490    } else if b == b'/' {
491        Ordering::Less
492    } else {
493        a.cmp(&b)
494    }
495}