1use crate::parser::scanner::{Range, ScanResult};
4use crate::{Error, Result};
5use smallvec::SmallVec;
6
7#[derive(Debug, Clone)]
9pub enum JsonValue<'a> {
10 Raw(&'a [u8]),
12 String(&'a str),
14 Number(&'a [u8]),
16 Bool(bool),
18 Null,
20 Array(LazyArray<'a>),
22 Object(LazyObject<'a>),
24}
25
26#[derive(Debug, Clone)]
28pub struct LazyArray<'a> {
29 raw: &'a [u8],
31 boundaries: SmallVec<[Range; 32]>,
33}
34
35#[derive(Debug, Clone)]
37pub struct LazyObject<'a> {
38 raw: &'a [u8],
40 fields: SmallVec<[FieldRange; 16]>,
42}
43
44#[derive(Debug, Clone)]
46pub struct FieldRange {
47 key: Range,
49 value: Range,
51}
52
53impl<'a> JsonValue<'a> {
54 pub fn as_str(&self) -> Option<&str> {
56 match self {
57 JsonValue::String(s) => Some(s),
58 _ => None,
59 }
60 }
61
62 pub fn as_f64(&self) -> Option<f64> {
64 match self {
65 JsonValue::Number(bytes) => std::str::from_utf8(bytes).ok()?.parse().ok(),
66 _ => None,
67 }
68 }
69
70 pub fn as_i64(&self) -> Option<i64> {
72 match self {
73 JsonValue::Number(bytes) => std::str::from_utf8(bytes).ok()?.parse().ok(),
74 _ => None,
75 }
76 }
77
78 pub fn as_bool(&self) -> Option<bool> {
80 match self {
81 JsonValue::Bool(b) => Some(*b),
82 _ => None,
83 }
84 }
85
86 pub fn is_null(&self) -> bool {
88 matches!(self, JsonValue::Null)
89 }
90
91 pub fn as_array(&self) -> Option<&LazyArray<'a>> {
93 match self {
94 JsonValue::Array(arr) => Some(arr),
95 _ => None,
96 }
97 }
98
99 pub fn as_object(&self) -> Option<&LazyObject<'a>> {
101 match self {
102 JsonValue::Object(obj) => Some(obj),
103 _ => None,
104 }
105 }
106
107 pub fn parse_raw(&mut self) -> Result<()> {
109 match self {
110 JsonValue::Raw(_bytes) => {
111 *self = JsonValue::Null; Ok(())
115 }
116 _ => Ok(()),
117 }
118 }
119}
120
121impl<'a> LazyArray<'a> {
122 pub fn from_scan(raw: &'a [u8], scan_result: ScanResult) -> Self {
124 let boundaries = Self::extract_element_boundaries(raw, &scan_result);
126
127 Self { raw, boundaries }
128 }
129
130 pub fn len(&self) -> usize {
132 self.boundaries.len()
133 }
134
135 pub fn is_empty(&self) -> bool {
137 self.boundaries.is_empty()
138 }
139
140 pub fn get(&self, index: usize) -> Option<&'a [u8]> {
142 if index >= self.boundaries.len() {
143 return None;
144 }
145
146 let range = self.boundaries[index];
147 Some(&self.raw[range.start..range.end])
148 }
149
150 pub fn get_parsed(&self, index: usize) -> Option<JsonValue<'a>> {
152 self.get(index).map(JsonValue::Raw)
153 }
154
155 pub fn iter(&'a self) -> LazyArrayIter<'a> {
157 LazyArrayIter {
158 array: self,
159 index: 0,
160 }
161 }
162
163 fn extract_element_boundaries(raw: &[u8], _scan_result: &ScanResult) -> SmallVec<[Range; 32]> {
175 let mut result = SmallVec::new();
176 let len = raw.len();
177
178 let mut pos = 0;
180 while pos < len && raw[pos] != b'[' {
181 pos += 1;
182 }
183 if pos == len {
184 return result;
185 }
186 pos += 1; let mut depth: usize = 1;
189 let mut in_string = false;
190 let mut elem_start: Option<usize> = None;
191
192 while pos < len {
193 let b = raw[pos];
194
195 if in_string {
196 if b == b'\\' {
197 pos += 1;
199 } else if b == b'"' {
200 in_string = false;
201 }
202 pos += 1;
203 continue;
204 }
205
206 match b {
207 b'"' => {
208 in_string = true;
209 if elem_start.is_none() {
210 elem_start = Some(pos);
211 }
212 }
213 b'[' | b'{' => {
214 depth += 1;
215 if elem_start.is_none() {
216 elem_start = Some(pos);
217 }
218 }
219 b']' | b'}' => {
220 depth -= 1;
221 if depth == 0 {
222 if let Some(start) = elem_start {
224 let end = trim_end(raw, start, pos);
225 if end > start {
226 result.push(Range::new(start, end));
227 }
228 }
229 break;
230 }
231 }
232 b',' if depth == 1 => {
233 if let Some(start) = elem_start {
235 let end = trim_end(raw, start, pos);
236 if end > start {
237 result.push(Range::new(start, end));
238 }
239 }
240 elem_start = None;
241 }
242 b' ' | b'\t' | b'\n' | b'\r' => {
243 pos += 1;
245 continue;
246 }
247 _ => {
248 if elem_start.is_none() {
249 elem_start = Some(pos);
250 }
251 }
252 }
253 pos += 1;
254 }
255
256 result
257 }
258
259 pub fn is_numeric(&self) -> bool {
261 self.boundaries.len() > 4
263 && self.boundaries.iter().take(3).all(|range| {
264 let slice = &self.raw[range.start..range.end];
265 self.looks_like_number(slice)
266 })
267 }
268
269 fn looks_like_number(&self, bytes: &[u8]) -> bool {
270 if bytes.is_empty() {
271 return false;
272 }
273
274 bytes.iter().all(|&b| {
275 b.is_ascii_digit() || b == b'.' || b == b'-' || b == b'+' || b == b'e' || b == b'E'
276 })
277 }
278}
279
280impl<'a> LazyObject<'a> {
281 pub fn from_scan(raw: &'a [u8], scan_result: ScanResult) -> Self {
283 let fields = Self::extract_field_boundaries(raw, &scan_result);
284
285 Self { raw, fields }
286 }
287
288 pub fn len(&self) -> usize {
290 self.fields.len()
291 }
292
293 pub fn is_empty(&self) -> bool {
295 self.fields.is_empty()
296 }
297
298 pub fn get(&self, key: &str) -> Option<&'a [u8]> {
300 let field_range = self.fields.iter().find(|field| {
302 let key_bytes = &self.raw[field.key.start..field.key.end];
303 std::str::from_utf8(key_bytes) == Ok(key)
304 })?;
305
306 Some(&self.raw[field_range.value.start..field_range.value.end])
308 }
309
310 pub fn keys(&self) -> Result<Vec<&str>> {
312 self.fields
313 .iter()
314 .map(|field| {
315 let key_bytes = &self.raw[field.key.start..field.key.end];
316 std::str::from_utf8(key_bytes).map_err(Error::from)
317 })
318 .collect()
319 }
320
321 fn extract_field_boundaries(
333 raw: &[u8],
334 _scan_result: &ScanResult,
335 ) -> SmallVec<[FieldRange; 16]> {
336 let mut result = SmallVec::new();
337 let len = raw.len();
338
339 let mut pos = 0;
341 while pos < len && raw[pos] != b'{' {
342 pos += 1;
343 }
344 if pos == len {
345 return result;
346 }
347 pos += 1; loop {
350 while pos < len && raw[pos].is_ascii_whitespace() {
352 pos += 1;
353 }
354 if pos >= len || raw[pos] == b'}' {
355 break;
356 }
357 if raw[pos] != b'"' {
358 break;
360 }
361 pos += 1; let key_start = pos;
363 while pos < len && raw[pos] != b'"' {
365 if raw[pos] == b'\\' {
366 pos += 1; }
368 pos += 1;
369 }
370 let key_end = pos;
371 if pos < len {
372 pos += 1; }
374
375 while pos < len && (raw[pos].is_ascii_whitespace() || raw[pos] == b':') {
377 pos += 1;
378 }
379 if pos >= len {
380 break;
381 }
382
383 let value_start = pos;
385 let mut depth: usize = 0;
386 let mut in_str = false;
387
388 while pos < len {
389 let b = raw[pos];
390 if in_str {
391 if b == b'\\' {
392 pos += 1; } else if b == b'"' {
394 in_str = false;
395 if depth == 0 {
396 pos += 1;
397 break;
398 }
399 }
400 pos += 1;
401 continue;
402 }
403 match b {
404 b'"' => {
405 in_str = true;
406 }
407 b'[' | b'{' => depth += 1,
408 b']' | b'}' => {
409 if depth == 0 {
410 break;
412 }
413 depth -= 1;
414 if depth == 0 {
415 pos += 1;
416 break;
417 }
418 }
419 b',' if depth == 0 => {
420 break;
422 }
423 _ => {}
424 }
425 pos += 1;
426 }
427
428 let value_end = trim_end(raw, value_start, pos);
429 if value_end > value_start {
430 result.push(FieldRange::new(
431 Range::new(key_start, key_end),
432 Range::new(value_start, value_end),
433 ));
434 }
435
436 while pos < len && (raw[pos].is_ascii_whitespace() || raw[pos] == b',') {
438 pos += 1;
439 }
440 }
441
442 result
443 }
444}
445
446pub struct LazyArrayIter<'a> {
448 array: &'a LazyArray<'a>,
449 index: usize,
450}
451
452impl<'a> Iterator for LazyArrayIter<'a> {
453 type Item = &'a [u8]; fn next(&mut self) -> Option<Self::Item> {
456 if self.index >= self.array.boundaries.len() {
457 return None;
458 }
459
460 let range = self.array.boundaries[self.index];
461 self.index += 1;
462
463 Some(&self.array.raw[range.start..range.end])
464 }
465}
466
467impl FieldRange {
468 pub fn new(key: Range, value: Range) -> Self {
470 Self { key, value }
471 }
472}
473
474fn trim_end(raw: &[u8], start: usize, end: usize) -> usize {
478 let mut e = end;
479 while e > start && raw[e - 1].is_ascii_whitespace() {
480 e -= 1;
481 }
482 e
483}
484
485#[cfg(test)]
486mod tests {
487 use super::*;
488
489 #[test]
490 fn test_json_value_types() {
491 let val = JsonValue::String("hello");
492 assert_eq!(val.as_str(), Some("hello"));
493 assert!(val.as_f64().is_none());
494 }
495
496 #[test]
497 fn test_lazy_array_creation() {
498 let raw = b"[1, 2, 3]";
499 let scan_result = ScanResult::new();
500 let array = LazyArray::from_scan(raw, scan_result);
501
502 assert_eq!(array.len(), 3);
503 assert_eq!(array.get(0), Some(b"1".as_ref()));
504 assert_eq!(array.get(1), Some(b"2".as_ref()));
505 assert_eq!(array.get(2), Some(b"3".as_ref()));
506 }
507
508 #[test]
509 fn test_lazy_array_empty() {
510 let array = LazyArray::from_scan(b"[]", ScanResult::new());
511 assert_eq!(array.len(), 0);
512 assert!(array.is_empty());
513 }
514
515 #[test]
516 fn test_lazy_array_strings() {
517 let raw = b"[\"hello\", \"world\"]";
518 let array = LazyArray::from_scan(raw, ScanResult::new());
519 assert_eq!(array.len(), 2);
520 assert_eq!(array.get(0), Some(b"\"hello\"".as_ref()));
521 }
522
523 #[test]
524 fn test_lazy_array_nested() {
525 let raw = b"[1, [2, 3], {\"a\": 4}]";
526 let array = LazyArray::from_scan(raw, ScanResult::new());
527 assert_eq!(array.len(), 3);
528 assert_eq!(array.get(0), Some(b"1".as_ref()));
529 assert_eq!(array.get(1), Some(b"[2, 3]".as_ref()));
530 assert_eq!(array.get(2), Some(b"{\"a\": 4}".as_ref()));
531 }
532
533 #[test]
534 fn test_lazy_array_escaped_string() {
535 let raw = br#"["say \"hi\"", "bye"]"#;
536 let array = LazyArray::from_scan(raw, ScanResult::new());
537 assert_eq!(array.len(), 2);
538 }
539
540 #[test]
541 fn test_lazy_object_creation() {
542 let obj = LazyObject::from_scan(b"{\"a\": 1, \"b\": 2}", ScanResult::new());
543 assert_eq!(obj.len(), 2);
544 assert_eq!(obj.get("a"), Some(b"1".as_ref()));
545 assert_eq!(obj.get("b"), Some(b"2".as_ref()));
546 }
547
548 #[test]
549 fn test_lazy_object_empty() {
550 let obj = LazyObject::from_scan(b"{}", ScanResult::new());
551 assert_eq!(obj.len(), 0);
552 assert!(obj.is_empty());
553 }
554
555 #[test]
556 fn test_lazy_object_string_value() {
557 let raw = b"{\"name\": \"alice\"}";
558 let obj = LazyObject::from_scan(raw, ScanResult::new());
559 assert_eq!(obj.len(), 1);
560 assert_eq!(obj.get("name"), Some(b"\"alice\"".as_ref()));
561 }
562
563 #[test]
564 fn test_lazy_object_nested_value() {
565 let raw = b"{\"arr\": [1, 2], \"n\": 42}";
566 let obj = LazyObject::from_scan(raw, ScanResult::new());
567 assert_eq!(obj.len(), 2);
568 assert_eq!(obj.get("arr"), Some(b"[1, 2]".as_ref()));
569 assert_eq!(obj.get("n"), Some(b"42".as_ref()));
570 }
571
572 #[test]
573 fn test_number_detection() {
574 let raw = b"[1.0, 2.5, 3.14]";
575 let scan_result = ScanResult::new();
576 let array = LazyArray::from_scan(raw, scan_result);
577
578 assert!(array.looks_like_number(b"123.45"));
579 assert!(!array.looks_like_number(b"\"string\""));
580 }
581}