ziyy_core/indexer/
mod.rs

1use std::{borrow::Cow, mem::take};
2
3// mod scanner;
4// mod token;
5
6/// The Indexer adds indices to empty placeholders
7pub struct Indexer<'a> {
8    source: &'a str,
9    start: usize,
10    current: usize,
11    parts: Vec<Cow<'a, str>>,
12}
13
14impl<'a> Default for Indexer<'a> {
15    fn default() -> Self {
16        Self::new()
17    }
18}
19
20impl<'a> Indexer<'a> {
21    pub fn new() -> Self {
22        Self {
23            source: "",
24            start: 0,
25            current: 0,
26            parts: Vec::new(),
27        }
28    }
29
30    pub fn index(&mut self, source: &'a str) -> Cow<'a, str> {
31        if !source.contains("{}") {
32            return Cow::Borrowed(source);
33        }
34
35        self.source = source;
36        self.parts = Vec::with_capacity(self.source.len() / 2);
37
38        let mut index = 0;
39        while !self.is_at_end() {
40            self.start = self.current;
41
42            if self.peek(0) == b'{' && self.peek(1) == b'{' {
43                self.advance(2);
44                self.add_part();
45            } else if self.peek(0) == b'{' && self.peek(1) == b'}' && self.peek(2) != b'}' {
46                self.advance(2);
47                self.parts.push(Cow::Borrowed("{"));
48                self.parts.push(Cow::Owned(index.to_string()));
49                self.parts.push(Cow::Borrowed("}"));
50                index += 1;
51            } else {
52                loop {
53                    self.advance(1);
54
55                    if self.is_at_end() {
56                        break;
57                    }
58                    if self.peek(0) == b'{' && self.peek(1) == b'{' {
59                        break;
60                    }
61                    if self.peek(0) == b'{' && self.peek(1) == b'}' && self.peek(2) != b'}' {
62                        break;
63                    }
64                }
65                self.add_part();
66            }
67        }
68        Cow::Owned(take(&mut self.parts).join(""))
69    }
70
71    fn peek(&self, n: usize) -> u8 {
72        if self.current + n >= self.source.len() {
73            b'\0'
74        } else {
75            self.source.as_bytes()[self.current + n]
76        }
77    }
78
79    fn is_at_end(&self) -> bool {
80        self.current >= self.source.len()
81    }
82
83    fn advance(&mut self, n: usize) {
84        self.current += n;
85    }
86
87    fn add_part(&mut self) {
88        let text = &self.source[self.start..self.current];
89        self.parts.push(Cow::Borrowed(text));
90    }
91}