1#[derive(Default)]
3pub struct EscapedScopeEval {
4 beg: char,
5 end: char,
6 esc_beg: char,
7 esc_end: char,
8}
9
10enum ScopeParseState {
12 Initial,
14 Parsing,
16 Escaped,
18}
19impl EscapedScopeEval {
20 #[inline(always)]
21 pub fn new(beg: char, end: char, esc_beg: char, esc_end: char) -> Self {
22 Self {
23 beg,
24 end,
25 esc_beg,
26 esc_end,
27 }
28 }
29 #[inline(always)]
30 pub fn len(&self, data: &str) -> usize {
31 let mut take_len = 0;
32 let mut mode = ScopeParseState::Initial;
33 let mut work_level = 0;
34 for c in data.chars() {
35 match mode {
36 ScopeParseState::Initial => {
37 if c == self.beg {
38 mode = ScopeParseState::Parsing;
39 work_level += 1;
40 take_len += 1;
41 continue;
42 } else {
43 break;
44 }
45 }
46 ScopeParseState::Parsing => {
47 if c == self.end {
48 take_len += 1;
49 work_level -= 1;
50 if work_level == 0 {
51 break;
52 }
53 continue;
54 }
55 if c == self.beg {
56 take_len += 1;
57 work_level += 1;
58 continue;
59 }
60 if c == self.esc_beg {
61 mode = ScopeParseState::Escaped;
62 take_len += 1;
63 continue;
64 }
65 take_len += 1;
66 }
67 ScopeParseState::Escaped => {
68 if c == self.esc_end {
69 mode = ScopeParseState::Parsing;
70 take_len += 1;
71 continue;
72 }
73 take_len += 1;
74 }
75 }
76 }
77 take_len
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use crate::scope::EscapedScopeEval;
84
85 mod escaped_scope {
86 use super::*;
87
88 #[test]
89 fn valid_escaped_content() {
90 let scope_rule = EscapedScopeEval::new('{', '}', '"', '"');
91 let data = r#"{ "a" : "} hello {" }"#;
92 let size = scope_rule.len(data);
93 assert_eq!(size, 21);
94 }
95
96 #[test]
97 fn valid_simple_scope() {
98 let scope_rule = EscapedScopeEval::new('{', '}', '"', '"');
99 let data = r#"{ "a" : 123 }"#;
100 let size = scope_rule.len(data);
101 assert_eq!(size, 13);
102 }
103
104 #[test]
105 fn valid_first_scope_only() {
106 let scope_rule = EscapedScopeEval::new('{', '}', '"', '"');
107 let data = r#"{ "a" : 123 } {"b" : 234 }"#;
108 let size = scope_rule.len(data);
109 assert_eq!(size, 13);
110 }
111
112 #[test]
113 fn invalid_leading_space() {
114 let scope_rule = EscapedScopeEval::new('{', '}', '"', '"');
115 let data = r#" { "a" : 123 } {"b" : 234 }"#;
116 let size = scope_rule.len(data);
117 assert_eq!(size, 0);
118 }
119
120 #[test]
121 fn valid_deeply_nested() {
122 let scope_rule = EscapedScopeEval::new('{', '}', '"', '"');
123 let data = r#"{ "a" : 123 , "b": { "x" : { "y" :1 }} }"#;
124 let size = scope_rule.len(data);
125 assert_eq!(size, 40);
126 }
127 }
128
129 mod edge_cases {
130 use super::*;
131
132 #[test]
133 fn empty_scope() {
134 let scope_rule = EscapedScopeEval::new('{', '}', '"', '"');
135 let data = "{}";
136 let size = scope_rule.len(data);
137 assert_eq!(size, 2);
138 }
139
140 #[test]
141 fn empty_input() {
142 let scope_rule = EscapedScopeEval::new('{', '}', '"', '"');
143 let data = "";
144 let size = scope_rule.len(data);
145 assert_eq!(size, 0);
146 }
147
148 #[test]
149 fn escaped_opening_delimiter() {
150 let scope_rule = EscapedScopeEval::new('{', '}', '"', '"');
151 let data = r#"{ "key": "{value}" }"#;
152 let size = scope_rule.len(data);
153 assert_eq!(size, 20);
154 }
155
156 #[test]
157 fn escaped_closing_delimiter() {
158 let scope_rule = EscapedScopeEval::new('{', '}', '"', '"');
159 let data = r#"{ "key": "val}ue" }"#;
160 let size = scope_rule.len(data);
161 assert_eq!(size, 19);
162 }
163
164 #[test]
165 fn multiple_escaped_sections() {
166 let scope_rule = EscapedScopeEval::new('{', '}', '"', '"');
167 let data = r#"{ "a": "}" , "b": "{" , "c": "}" }"#;
168 let size = scope_rule.len(data);
169 assert_eq!(size, 34);
170 }
171
172 #[test]
173 fn unmatched_opening() {
174 let scope_rule = EscapedScopeEval::new('{', '}', '"', '"');
175 let data = r#"{ "key": "value" "#;
176 let size = scope_rule.len(data);
177 assert_eq!(
179 size, 17,
180 "Continues to end without finding closing delimiter"
181 );
182 }
183
184 #[test]
185 fn nested_with_escape() {
186 let scope_rule = EscapedScopeEval::new('{', '}', '"', '"');
187 let data = r#"{ "outer": { "inner": "}" } }"#;
188 let size = scope_rule.len(data);
189 assert_eq!(size, 29);
190 }
191 }
192
193 mod different_escape_delimiters {
194 use super::*;
195
196 #[test]
197 fn single_quote_escape() {
198 let scope_rule = EscapedScopeEval::new('{', '}', '\'', '\'');
199 let data = r#"{ 'key': 'val}ue' }"#;
200 let size = scope_rule.len(data);
201 assert_eq!(size, 19);
202 }
203
204 #[test]
205 fn parentheses_with_string_escape() {
206 let scope_rule = EscapedScopeEval::new('(', ')', '"', '"');
207 let data = r#"(a ")" b)"#;
208 let size = scope_rule.len(data);
209 assert_eq!(size, 9);
210 }
211
212 #[test]
213 fn brackets_with_escape() {
214 let scope_rule = EscapedScopeEval::new('[', ']', '"', '"');
215 let data = r#"["item]", "other"]"#;
216 let size = scope_rule.len(data);
217 assert_eq!(size, 18);
218 }
219 }
220
221 mod boundary_conditions {
222 use super::*;
223
224 #[test]
225 fn only_escape_chars() {
226 let scope_rule = EscapedScopeEval::new('{', '}', '"', '"');
227 let data = r#"{ "" }"#;
228 let size = scope_rule.len(data);
229 assert_eq!(size, 6);
230 }
231
232 #[test]
233 fn nested_escape_sections() {
234 let scope_rule = EscapedScopeEval::new('{', '}', '"', '"');
235 let data = r#"{ "a": "\"nested\"" }"#;
236 let size = scope_rule.len(data);
237 assert_eq!(size, 21);
239 }
240
241 #[test]
242 fn whitespace_in_escaped() {
243 let scope_rule = EscapedScopeEval::new('{', '}', '"', '"');
244 let data = r#"{ " spaces " }"#;
245 let size = scope_rule.len(data);
246 assert_eq!(size, 16);
247 }
248
249 #[test]
250 fn newlines_in_escaped() {
251 let scope_rule = EscapedScopeEval::new('{', '}', '"', '"');
252 let data = "{ \"line1\nline2\" }";
253 let size = scope_rule.len(data);
254 assert_eq!(size, 17);
255 }
256 }
257}