promkit_widgets/jsonstream/
jsonz.rs1use rayon::prelude::*;
2
3#[derive(Clone, Debug, PartialEq)]
4pub enum ContainerType {
5 Object,
6 Array,
7}
8
9impl ContainerType {
10 pub fn open_str(&self) -> &'static str {
11 match self {
12 ContainerType::Object => "{",
13 ContainerType::Array => "[",
14 }
15 }
16
17 pub fn close_str(&self) -> &'static str {
18 match self {
19 ContainerType::Object => "}",
20 ContainerType::Array => "]",
21 }
22 }
23
24 pub fn empty_str(&self) -> &'static str {
25 match self {
26 ContainerType::Object => "{}",
27 ContainerType::Array => "[]",
28 }
29 }
30
31 pub fn collapsed_preview(&self) -> &'static str {
32 match self {
33 ContainerType::Object => "{…}",
34 ContainerType::Array => "[…]",
35 }
36 }
37}
38
39#[derive(Clone, Debug, PartialEq)]
40pub enum Value {
41 Null,
42 Boolean(bool),
43 Number(serde_json::Number),
44 String(String),
45 Empty {
46 typ: ContainerType,
47 },
48 Open {
49 typ: ContainerType,
50 collapsed: bool,
51 close_index: usize,
52 },
53 Close {
54 typ: ContainerType,
55 collapsed: bool,
56 open_index: usize,
57 },
58}
59
60#[derive(Clone, Debug, PartialEq)]
61pub struct Row {
62 pub depth: usize,
63 pub k: Option<String>,
64 pub v: Value,
65}
66
67pub trait RowOperation {
68 fn up(&self, current: usize) -> usize;
69 fn head(&self) -> usize;
70 fn down(&self, current: usize) -> usize;
71 fn tail(&self) -> usize;
72 fn toggle(&mut self, current: usize) -> usize;
73 fn set_rows_visibility(&mut self, collapsed: bool);
74 fn extract(&self, current: usize, n: usize) -> Vec<Row>;
75}
76
77impl RowOperation for Vec<Row> {
78 fn up(&self, current: usize) -> usize {
79 if current == 0 {
80 return 0;
81 }
82
83 let prev = current - 1;
84 match &self[prev].v {
85 Value::Close {
86 collapsed,
87 open_index,
88 ..
89 } if *collapsed => *open_index,
90 _ => prev,
91 }
92 }
93
94 fn head(&self) -> usize {
95 0
96 }
97
98 fn down(&self, current: usize) -> usize {
99 if current >= self.len() - 1 {
100 return current;
101 }
102
103 let next = current + 1;
104 match &self[current].v {
105 Value::Open {
106 collapsed,
107 close_index,
108 ..
109 } if *collapsed => {
110 let next_pos = close_index + 1;
111 if next_pos >= self.len() {
112 current
113 } else {
114 next_pos
115 }
116 }
117 _ => next,
118 }
119 }
120
121 fn tail(&self) -> usize {
122 if self.is_empty() {
123 return 0;
124 }
125
126 let mut last = self.len() - 1;
127 match &self[last].v {
128 Value::Close {
129 collapsed,
130 open_index,
131 ..
132 } if *collapsed => {
133 last = *open_index;
134 last
135 }
136 _ => last,
137 }
138 }
139
140 fn toggle(&mut self, current: usize) -> usize {
141 match &self[current].v {
142 Value::Open {
143 typ,
144 collapsed,
145 close_index,
146 } => {
147 let new_collapsed = !collapsed;
148 let close_idx = *close_index;
149 let typ_clone = typ.clone();
150
151 self[current].v = Value::Open {
152 typ: typ_clone.clone(),
153 collapsed: new_collapsed,
154 close_index: close_idx,
155 };
156
157 self[close_idx].v = Value::Close {
158 typ: typ_clone,
159 collapsed: new_collapsed,
160 open_index: current,
161 };
162
163 current
164 }
165 Value::Close {
166 typ,
167 collapsed,
168 open_index,
169 } => {
170 let new_collapsed = !collapsed;
171 let open_idx = *open_index;
172 let typ_clone = typ.clone();
173
174 self[current].v = Value::Close {
175 typ: typ_clone.clone(),
176 collapsed: new_collapsed,
177 open_index: open_idx,
178 };
179
180 self[open_idx].v = Value::Open {
181 typ: typ_clone,
182 collapsed: new_collapsed,
183 close_index: current,
184 };
185
186 if new_collapsed { open_idx } else { current }
187 }
188 _ => current,
189 }
190 }
191
192 fn set_rows_visibility(&mut self, collapsed: bool) {
193 self.par_iter_mut().for_each(|row| {
194 if let Value::Open {
195 typ, close_index, ..
196 } = &row.v
197 {
198 row.v = Value::Open {
199 typ: typ.clone(),
200 collapsed,
201 close_index: *close_index,
202 };
203 } else if let Value::Close {
204 typ, open_index, ..
205 } = &row.v
206 {
207 row.v = Value::Close {
208 typ: typ.clone(),
209 collapsed,
210 open_index: *open_index,
211 };
212 }
213 });
214 }
215
216 fn extract(&self, current: usize, n: usize) -> Vec<Row> {
217 let mut result = Vec::new();
218 let mut i = current;
219 let mut remaining = n;
220
221 while i < self.len() && remaining > 0 {
222 result.push(self[i].clone());
223 remaining -= 1;
224
225 match &self[i].v {
226 Value::Open {
227 collapsed: true,
228 close_index,
229 ..
230 } => {
231 i = *close_index + 1;
232 }
233 _ => {
234 i += 1;
235 }
236 }
237 }
238
239 result
240 }
241}
242
243fn process_value(
244 value: &serde_json::Value,
245 rows: &mut Vec<Row>,
246 depth: usize,
247 key: Option<String>,
248) -> usize {
249 match value {
250 serde_json::Value::Null => {
251 rows.push(Row {
252 depth,
253 k: key,
254 v: Value::Null,
255 });
256 rows.len() - 1
257 }
258 serde_json::Value::Bool(b) => {
259 rows.push(Row {
260 depth,
261 k: key,
262 v: Value::Boolean(*b),
263 });
264 rows.len() - 1
265 }
266 serde_json::Value::Number(n) => {
267 rows.push(Row {
268 depth,
269 k: key,
270 v: Value::Number(n.clone()),
271 });
272 rows.len() - 1
273 }
274 serde_json::Value::String(s) => {
275 rows.push(Row {
276 depth,
277 k: key,
278 v: Value::String(s.clone()),
279 });
280 rows.len() - 1
281 }
282 serde_json::Value::Array(arr) => {
283 if arr.is_empty() {
284 rows.push(Row {
285 depth,
286 k: key,
287 v: Value::Empty {
288 typ: ContainerType::Array,
289 },
290 });
291 return rows.len() - 1;
292 }
293
294 let open_index = rows.len();
295
296 rows.push(Row {
297 depth,
298 k: key,
299 v: Value::Open {
300 typ: ContainerType::Array,
301 collapsed: false,
302 close_index: 0,
303 },
304 });
305
306 for value in arr {
307 process_value(value, rows, depth + 1, None);
308 }
309
310 let close_index = rows.len();
311 rows.push(Row {
312 depth,
313 k: None,
314 v: Value::Close {
315 typ: ContainerType::Array,
316 collapsed: false,
317 open_index,
318 },
319 });
320
321 rows[open_index].v = Value::Open {
322 typ: ContainerType::Array,
323 collapsed: false,
324 close_index,
325 };
326
327 open_index
328 }
329 serde_json::Value::Object(obj) => {
330 if obj.is_empty() {
331 rows.push(Row {
332 depth,
333 k: key,
334 v: Value::Empty {
335 typ: ContainerType::Object,
336 },
337 });
338 return rows.len() - 1;
339 }
340
341 let open_index = rows.len();
342
343 rows.push(Row {
344 depth,
345 k: key,
346 v: Value::Open {
347 typ: ContainerType::Object,
348 collapsed: false,
349 close_index: 0,
350 },
351 });
352
353 for (key, value) in obj {
354 process_value(value, rows, depth + 1, Some(key.clone()));
355 }
356
357 let close_index = rows.len();
358 rows.push(Row {
359 depth,
360 k: None,
361 v: Value::Close {
362 typ: ContainerType::Object,
363 collapsed: false,
364 open_index,
365 },
366 });
367
368 rows[open_index].v = Value::Open {
369 typ: ContainerType::Object,
370 collapsed: false,
371 close_index,
372 };
373
374 open_index
375 }
376 }
377}
378
379pub fn create_rows<'a, T: IntoIterator<Item = &'a serde_json::Value>>(iter: T) -> Vec<Row> {
380 let mut rows = Vec::new();
381 for value in iter {
382 process_value(value, &mut rows, 0, None);
383 }
384 rows
385}
386
387#[derive(Debug)]
388pub struct PathIterator<'a> {
389 stack: Vec<(String, &'a serde_json::Value)>,
390}
391
392impl PathIterator<'_> {
393 fn escape_json_path_key(key: &str) -> String {
394 if key.contains('.') || key.contains('-') || key.contains('@') {
395 format!("\"{}\"", key)
396 } else {
397 key.to_string()
398 }
399 }
400}
401
402impl Iterator for PathIterator<'_> {
403 type Item = String;
404
405 fn next(&mut self) -> Option<Self::Item> {
406 if let Some((current_path, value)) = self.stack.pop() {
407 match value {
408 serde_json::Value::Object(obj) => {
409 for (key, val) in obj.iter() {
410 let escaped = Self::escape_json_path_key(key);
411 let new_path = if current_path == "." {
412 format!(".{}", escaped)
413 } else {
414 format!("{}.{}", current_path, escaped)
415 };
416 self.stack.push((new_path, val));
417 }
418 }
419 serde_json::Value::Array(arr) => {
420 for (i, val) in arr.iter().enumerate() {
421 let new_path = format!("{}[{}]", current_path, i);
422 self.stack.push((new_path, val));
423 }
424 }
425 _ => {}
426 }
427
428 Some(current_path)
429 } else {
430 None
431 }
432 }
433}
434
435pub fn get_all_paths<'a, T: IntoIterator<Item = &'a serde_json::Value>>(
436 iter: T,
437) -> impl Iterator<Item = String> + 'a {
438 let mut stack = Vec::new();
439 for value in iter {
440 stack.push((".".to_string(), value));
441 }
442 PathIterator { stack }
443}