1use crate::style::{PresetStyle, Style};
2use serde_json::Value;
3use std::collections::VecDeque;
4
5#[derive(Debug, PartialEq)]
7pub struct Element<'a> {
8 pub path: String,
10 pub indices: Vec<usize>,
12 pub value: &'a Value,
14}
15
16#[derive(Debug)]
18pub struct Iter<'a> {
19 style: Style<'a>,
20 items: VecDeque<Element<'a>>,
21}
22
23impl<'a> Iter<'a> {
25 pub fn new(json: &'a Value) -> Self {
40 let mut queue = VecDeque::new();
41 queue.push_back(Element {
42 path: String::from(""),
43 indices: Vec::new(),
44 value: json,
45 });
46
47 Self {
48 items: queue,
49 style: PresetStyle::SquareBrackets.into(),
50 }
51 }
52
53 pub fn use_style(mut self, style: Style<'a>) -> Self {
70 self.style = style;
71 self
72 }
73}
74
75impl<'a> From<&'a Value> for Iter<'a> {
76 fn from(item: &'a Value) -> Iter<'a> {
77 Iter::new(item)
78 }
79}
80
81impl<'a> Iterator for Iter<'a> {
82 type Item = Element<'a>;
83
84 fn next(&mut self) -> Option<Self::Item> {
85 'items: while let Some(el) = self.items.pop_front() {
86 match el.value {
87 Value::Object(obj) => {
88 for (key, val) in obj.iter().rev() {
89 self.items.push_front(Element {
90 path: self.style.object_format(&el.path, key),
91 indices: el.indices.clone(),
92 value: val,
93 });
94 }
95
96 match self.style.should_skip_object_parents() {
97 true => continue 'items,
98 false => return Some(el),
99 };
100 }
101 Value::Array(arr) => {
102 for (index, val) in arr.iter().enumerate().rev() {
103 let mut indices_vec = el.indices.to_vec();
104 indices_vec.push(index);
105
106 self.items.push_front(Element {
107 path: self.style.array_format(&el.path, index),
108 indices: indices_vec,
109 value: val,
110 });
111 }
112
113 match self.style.should_skip_array_parents() {
114 true => continue 'items,
115 false => return Some(el),
116 };
117 }
118 _ => return Some(el),
119 }
120 }
121 None
122 }
123}
124
125#[cfg(test)]
126mod tests {
127 use super::*;
128 use crate::style::StyleBuilder;
129 use serde_json::json;
130
131 #[test]
132 fn null_to_iter() {
133 let value = json!(null);
134 let items: Vec<_> = Iter::new(&value).collect();
135
136 assert_eq!(items.len(), 1);
137 assert_eq!(
138 items[0],
139 Element {
140 path: String::from(""),
141 indices: Vec::new(),
142 value: &Value::Null,
143 }
144 );
145 }
146
147 #[test]
148 fn bool_to_iter() {
149 let value = json!(true);
150 let items: Vec<_> = Iter::new(&value).collect();
151
152 assert_eq!(items.len(), 1);
153 assert_eq!(
154 items[0],
155 Element {
156 path: String::from(""),
157 indices: Vec::new(),
158 value: &Value::Bool(true),
159 }
160 );
161 }
162
163 #[test]
164 fn number_to_iter() {
165 let value = json!(42);
166 let items: Vec<_> = Iter::new(&value).collect();
167
168 assert_eq!(items.len(), 1);
169 assert_eq!(
170 items[0],
171 Element {
172 path: String::from(""),
173 indices: Vec::new(),
174 value: &Value::Number(42.into()),
175 }
176 );
177 }
178
179 #[test]
180 fn string_to_iter() {
181 let value = json!("Hello there!");
182 let items: Vec<_> = Iter::new(&value).collect();
183
184 assert_eq!(items.len(), 1);
185 assert_eq!(
186 items[0],
187 Element {
188 path: String::from(""),
189 indices: Vec::new(),
190 value: &Value::String("Hello there!".into()),
191 }
192 );
193 }
194
195 #[test]
196 fn array_to_iter() {
197 let value = json!([null, null]);
198 let style = StyleBuilder::new().include_array_parents().build();
199 let items: Vec<_> = Iter::new(&value).use_style(style).collect();
200
201 assert_eq!(items.len(), 3);
202 assert_eq!(
203 items[0],
204 Element {
205 path: String::from(""),
206 indices: Vec::new(),
207 value: &Value::Array(vec![Value::Null, Value::Null]),
208 }
209 );
210 }
211
212 #[test]
213 fn object_to_iter() {
214 let value = json!({ "a": true, "b": false });
215 let style = StyleBuilder::new().include_object_parents().build();
216 let items: Vec<_> = Iter::new(&value).use_style(style).collect();
217
218 assert_eq!(items.len(), 3);
219 assert_eq!(
220 items[0],
221 Element {
222 path: String::from(""),
223 indices: Vec::new(),
224 value: &json!({ "a": true, "b": false }),
225 }
226 );
227 }
228
229 #[test]
230 fn can_skip_parents() {
231 let value = json!({
232 "first": [1, 2, 3],
233 "middle": true,
234 "last": ["a", "b", "c"],
235 });
236 let style = StyleBuilder::new()
237 .skip_object_parents()
238 .skip_array_parents()
239 .build();
240 let items: Vec<_> = Iter::new(&value).use_style(style).collect();
241
242 assert_eq!(items.len(), 7);
243 assert_eq!(
244 items[2],
245 Element {
246 path: String::from("[\"first\"][2]"),
247 indices: vec![2],
248 value: &Value::Number(3.into()),
249 }
250 );
251 assert_eq!(
252 items[5],
253 Element {
254 path: String::from("[\"last\"][2]"),
255 indices: vec![2],
256 value: &Value::String("c".into()),
257 }
258 );
259 }
260
261 #[test]
262 fn custom_style_on_iter() {
263 let value = json!({
264 "first": [1, 2, 3],
265 });
266 let style = StyleBuilder::new()
267 .object_key_prefix("!")
268 .object_key_suffix("@")
269 .show_object_keys_in_path()
270 .include_object_parents()
271 .array_key_prefix("#")
272 .array_key_suffix("$")
273 .hide_array_keys_in_path()
274 .include_array_parents()
275 .build();
276 let items: Vec<_> = Iter::new(&value).use_style(style).collect();
277
278 assert_eq!(items.len(), 5);
279 assert_eq!(
280 items[3],
281 Element {
282 path: String::from("!first@#$"),
283 indices: vec![1],
284 value: &Value::Number(2.into()),
285 }
286 );
287 }
288
289 #[test]
290 fn complex_format_on_iter() {
291 let value = json!({
292 "first": [1, 2, 3],
293 "middle": true,
294 "last": ["a", "b", "c"],
295 });
296 let style = StyleBuilder::new()
297 .include_object_parents()
298 .include_array_parents()
299 .build();
300 let items: Vec<_> = Iter::new(&value).use_style(style).collect();
301
302 assert_eq!(items.len(), 10);
303 assert_eq!(
304 items[2],
305 Element {
306 path: String::from("[\"first\"][0]"),
307 indices: vec![0],
308 value: &Value::Number(1.into()),
309 }
310 );
311 assert_eq!(
312 items[5],
313 Element {
314 path: String::from("[\"last\"]"),
315 indices: Vec::new(),
316 value: &Value::Array(vec!["a".into(), "b".into(), "c".into()]),
317 }
318 );
319 assert_eq!(
320 items[8],
321 Element {
322 path: String::from("[\"last\"][2]"),
323 indices: vec![2],
324 value: &Value::String("c".into()),
325 }
326 );
327
328 assert_eq!(
330 items[9],
331 Element {
332 path: String::from("[\"middle\"]"),
333 indices: Vec::new(),
334 value: &Value::Bool(true),
335 }
336 );
337 }
338
339 #[test]
340 fn in_a_for_loop() {
341 let value = json!({
342 "first": [1, 2, 3],
343 "middle": true,
344 "last": ["a", "b", "c"],
345 });
346
347 let mut collection = Vec::new();
348 let style = StyleBuilder::new()
349 .include_object_parents()
350 .include_array_parents()
351 .build();
352 for item in Iter::new(&value).use_style(style) {
353 collection.push(item);
354 }
355
356 assert_eq!(collection.len(), 10);
357 assert_eq!(
358 collection[2],
359 Element {
360 path: String::from("[\"first\"][0]"),
361 indices: vec![0],
362 value: &Value::Number(1.into()),
363 }
364 );
365 assert_eq!(
366 collection[5],
367 Element {
368 path: String::from("[\"last\"]"),
369 indices: Vec::new(),
370 value: &Value::Array(vec!["a".into(), "b".into(), "c".into()]),
371 }
372 );
373 assert_eq!(
374 collection[8],
375 Element {
376 path: String::from("[\"last\"][2]"),
377 indices: vec![2],
378 value: &Value::String("c".into()),
379 }
380 );
381
382 assert_eq!(
384 collection[9],
385 Element {
386 path: String::from("[\"middle\"]"),
387 indices: Vec::new(),
388 value: &Value::Bool(true),
389 }
390 );
391 }
392}