1use core::cmp::Ordering;
9
10use crate::head::{self, ARRAY, COUNT_MAX, DEPTH_MAX, INTERNED, Kind, OFFSETS, SORTED, Tag};
11
12#[derive(Clone, Copy)]
19pub struct Value<'a> {
20 b: &'a [u8],
21}
22
23impl<'a> Value<'a> {
24 #[must_use]
32 pub fn new(bytes: &'a [u8]) -> Option<Value<'a>> {
33 let v = Value { b: bytes };
34 let h = head::read(bytes, 0)?;
35 let tag = Tag::of(h)?;
36 if matches!(tag, Tag::Container) {
37 if h & OFFSETS == 0 || head::count(h) > COUNT_MAX {
38 return None;
39 }
40 let end = v.entries_end()?;
43 if bytes.len() < end {
44 return None;
45 }
46 } else if bytes.len() < 4 + head::count(h) {
47 return None;
48 }
49 Some(v)
50 }
51
52 #[must_use]
54 pub fn kind(&self) -> Kind {
55 match self.tag() {
56 Tag::Null => Kind::Null,
57 Tag::False | Tag::True => Kind::Bool,
58 Tag::Int => Kind::Int,
59 Tag::Float => Kind::Float,
60 Tag::Text => Kind::Text,
61 Tag::Container if self.head() & ARRAY == 0 => Kind::Object,
62 Tag::Container => Kind::Array,
63 }
64 }
65
66 #[must_use]
68 pub fn is_null(&self) -> bool {
69 matches!(self.tag(), Tag::Null)
70 }
71
72 #[must_use]
74 pub fn as_bool(&self) -> Option<bool> {
75 match self.tag() {
76 Tag::False => Some(false),
77 Tag::True => Some(true),
78 _ => None,
79 }
80 }
81
82 #[must_use]
88 pub fn as_int(&self) -> Option<i64> {
89 if !matches!(self.tag(), Tag::Int) {
90 return None;
91 }
92 let raw = self.payload()?;
93 Some(match raw.len() {
94 1 => i64::from(raw[0] as i8),
95 2 => i64::from(i16::from_le_bytes(raw.try_into().ok()?)),
96 4 => i64::from(i32::from_le_bytes(raw.try_into().ok()?)),
97 8 => i64::from_le_bytes(raw.try_into().ok()?),
98 _ => return None,
99 })
100 }
101
102 #[must_use]
104 pub fn as_float(&self) -> Option<f64> {
105 if !matches!(self.tag(), Tag::Float) {
106 return None;
107 }
108 let raw = self.payload()?;
109 Some(f64::from_le_bytes(raw.try_into().ok()?))
110 }
111
112 #[must_use]
114 pub fn as_text(&self) -> Option<&'a str> {
115 core::str::from_utf8(self.text_bytes()?).ok()
116 }
117
118 #[must_use]
124 pub fn text_bytes(&self) -> Option<&'a [u8]> {
125 if !matches!(self.tag(), Tag::Text) {
126 return None;
127 }
128 self.payload()
129 }
130
131 #[must_use]
133 pub fn len(&self) -> usize {
134 if matches!(self.tag(), Tag::Container) {
135 head::count(self.head())
136 } else {
137 0
138 }
139 }
140
141 #[must_use]
145 pub fn is_empty(&self) -> bool {
146 matches!(self.tag(), Tag::Container) && self.len() == 0
147 }
148
149 #[must_use]
155 pub fn is_interned(&self) -> bool {
156 self.is_container() && self.head() & INTERNED != 0
157 }
158
159 #[must_use]
165 pub fn at(&self, i: usize) -> Option<Value<'a>> {
166 let (_, off) = self.entry(i)?;
167 let child = self.b.get(off..)?;
168 Value::new(child)
169 }
170
171 #[must_use]
174 pub fn key_at(&self, i: usize) -> Option<&'a [u8]> {
175 if !self.is_object() || self.is_interned() {
176 return None;
177 }
178 let at = self.key_off(i)?;
179 let end = self.key_end(i)?;
180 self.b.get(at..end)
181 }
182
183 #[must_use]
186 pub fn key_id_at(&self, i: usize) -> Option<u16> {
187 if !self.is_interned() {
188 return None;
189 }
190 let at = 4 + i * 2;
191 let raw = self.b.get(at..at + 2)?;
192 Some(u16::from_le_bytes(raw.try_into().expect("two bytes")))
193 }
194
195 #[must_use]
202 pub fn get(&self, key: &[u8]) -> Option<Value<'a>> {
203 self.at(self.find(key)?)
204 }
205
206 #[must_use]
208 pub fn find(&self, key: &[u8]) -> Option<usize> {
209 if !self.is_object() || self.is_interned() {
210 return None;
211 }
212 let n = self.len();
213 if self.head() & SORTED == 0 {
214 return (0..n).find(|&i| self.key_at(i) == Some(key));
215 }
216 let (mut lo, mut hi) = (0usize, n);
217 while lo < hi {
218 let mid = (lo + hi) / 2;
219 match key_order(self.key_at(mid)?, key) {
220 Ordering::Less => lo = mid + 1,
221 Ordering::Greater => hi = mid,
222 Ordering::Equal => return Some(mid),
223 }
224 }
225 None
226 }
227
228 #[must_use]
230 pub fn get_id(&self, id: u16) -> Option<Value<'a>> {
231 self.at(self.find_id(id)?)
232 }
233
234 #[must_use]
236 pub fn find_id(&self, id: u16) -> Option<usize> {
237 if !self.is_interned() {
238 return None;
239 }
240 let n = self.len();
241 if self.head() & SORTED == 0 {
242 return (0..n).find(|&i| self.key_id_at(i) == Some(id));
243 }
244 let (mut lo, mut hi) = (0usize, n);
245 while lo < hi {
246 let mid = (lo + hi) / 2;
247 match self.key_id_at(mid)?.cmp(&id) {
248 Ordering::Less => lo = mid + 1,
249 Ordering::Greater => hi = mid,
250 Ordering::Equal => return Some(mid),
251 }
252 }
253 None
254 }
255
256 #[must_use]
258 pub fn iter(&self) -> Elems<'a> {
259 Elems { v: *self, i: 0 }
260 }
261
262 #[must_use]
267 pub fn members(&self) -> Members<'a> {
268 Members { v: *self, i: 0 }
269 }
270
271 #[must_use]
278 pub fn encoded_len(&self) -> Option<usize> {
279 self.encoded_len_at(0)
280 }
281
282 fn encoded_len_at(&self, depth: usize) -> Option<usize> {
283 if depth > DEPTH_MAX {
284 return None;
285 }
286 let h = self.head();
287 if !matches!(Tag::of(h)?, Tag::Container) {
288 return Some(4 + head::count(h));
289 }
290 let n = head::count(h);
291 if n == 0 {
292 return self.entries_end();
293 }
294 let (_, off) = self.entry(n - 1)?;
295 let last = Value::new(self.b.get(off..)?)?;
296 off.checked_add(last.encoded_len_at(depth + 1)?)
297 }
298
299 #[must_use]
310 pub fn offset_in(&self, root: &Value<'_>) -> Option<usize> {
311 let here = self.b.as_ptr() as usize;
312 let base = root.b.as_ptr() as usize;
313 let off = here.checked_sub(base)?;
314 (off < root.b.len()).then_some(off)
315 }
316
317 #[must_use]
319 pub fn as_bytes(&self) -> Option<&'a [u8]> {
320 self.b.get(..self.encoded_len()?)
321 }
322
323 #[must_use]
331 pub fn validate(&self) -> bool {
332 self.validate_at(0)
333 }
334
335 fn validate_at(&self, depth: usize) -> bool {
336 if depth > DEPTH_MAX {
337 return false;
338 }
339 let Some(h) = head::read(self.b, 0) else {
340 return false;
341 };
342 let Some(tag) = Tag::of(h) else {
343 return false;
344 };
345 if !matches!(tag, Tag::Container) {
346 let n = head::count(h);
347 if matches!(tag, Tag::Int) && !matches!(n, 1 | 2 | 4 | 8) {
348 return false;
349 }
350 if matches!(tag, Tag::Float) && n != 8 {
351 return false;
352 }
353 if matches!(tag, Tag::Null | Tag::False | Tag::True) && n != 0 {
354 return false;
355 }
356 return self.b.len() >= 4 + n;
357 }
358 if h & OFFSETS == 0 {
359 return false;
360 }
361 let n = head::count(h);
362 let Some(mut want) = self.entries_end() else {
363 return false;
364 };
365 if self.b.len() < want {
366 return false;
367 }
368 if self.is_object() && !self.is_interned() {
369 for i in 0..n {
372 let (Some(at), Some(end)) = (self.key_off(i), self.key_end(i)) else {
373 return false;
374 };
375 if at != want || end < at || self.b.len() < end {
376 return false;
377 }
378 want = end;
379 }
380 }
381 for i in 0..n {
382 let Some((copy, off)) = self.entry(i) else {
383 return false;
384 };
385 if off != want {
388 return false;
389 }
390 let Some(child) = self.b.get(off..).and_then(Value::new) else {
391 return false;
392 };
393 if child.head() != copy || !child.validate_at(depth + 1) {
394 return false;
395 }
396 let Some(len) = child.encoded_len_at(depth + 1) else {
397 return false;
398 };
399 want = off + len;
400 }
401 if self.is_object() && h & SORTED != 0 && !self.keys_ascend(n) {
402 return false;
403 }
404 true
405 }
406
407 fn head(&self) -> u32 {
409 head::read(self.b, 0).unwrap_or(0)
410 }
411
412 fn tag(&self) -> Tag {
413 Tag::of(self.head()).unwrap_or(Tag::Null)
414 }
415
416 fn is_container(&self) -> bool {
417 matches!(self.tag(), Tag::Container)
418 }
419
420 fn is_object(&self) -> bool {
421 self.is_container() && self.head() & ARRAY == 0
422 }
423
424 fn payload(&self) -> Option<&'a [u8]> {
426 let n = head::count(self.head());
427 self.b.get(4..4 + n)
428 }
429
430 fn entries_at(&self) -> usize {
432 4 + crate::layout::keys_area(self.head(), self.len())
433 }
434
435 fn entries_end(&self) -> Option<usize> {
437 self.entries_at().checked_add(self.len().checked_mul(8)?)
438 }
439
440 fn entry(&self, i: usize) -> Option<(u32, usize)> {
442 if !self.is_container() || i >= self.len() {
443 return None;
444 }
445 let at = self.entries_at() + i * 8;
446 let copy = head::read(self.b, at)?;
447 let off = head::read(self.b, at + 4)? as usize;
448 if off < self.entries_end()? {
453 return None;
454 }
455 Some((copy, off))
456 }
457
458 fn key_off(&self, i: usize) -> Option<usize> {
460 if i >= self.len() {
461 return None;
462 }
463 Some(head::read(self.b, 4 + i * 4)? as usize)
464 }
465
466 fn key_end(&self, i: usize) -> Option<usize> {
472 if i + 1 < self.len() {
473 self.key_off(i + 1)
474 } else {
475 self.entry(0).map(|(_, off)| off)
476 }
477 }
478
479 fn keys_ascend(&self, n: usize) -> bool {
480 for i in 1..n {
481 let ord = if self.is_interned() {
482 match (self.key_id_at(i - 1), self.key_id_at(i)) {
483 (Some(a), Some(b)) => a.cmp(&b),
484 _ => return false,
485 }
486 } else {
487 match (self.key_at(i - 1), self.key_at(i)) {
488 (Some(a), Some(b)) => key_order(a, b),
489 _ => return false,
490 }
491 };
492 if ord != Ordering::Less {
493 return false;
494 }
495 }
496 true
497 }
498}
499
500impl core::fmt::Debug for Value<'_> {
501 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
502 match self.kind() {
503 Kind::Null => f.write_str("null"),
504 Kind::Bool => write!(f, "{}", self.as_bool().unwrap_or(false)),
505 Kind::Int => write!(f, "{}", self.as_int().unwrap_or(0)),
506 Kind::Float => write!(f, "{}", self.as_float().unwrap_or(0.0)),
507 Kind::Text => write!(f, "{:?}", self.as_text().unwrap_or("")),
508 Kind::Array => f.debug_list().entries(self.iter()).finish(),
509 Kind::Object => {
510 let mut m = f.debug_map();
511 for (k, v) in self.members() {
512 m.entry(&String::from_utf8_lossy(k), &v);
513 }
514 m.finish()
515 }
516 }
517 }
518}
519
520#[must_use]
527pub fn key_order(a: &[u8], b: &[u8]) -> Ordering {
528 a.len().cmp(&b.len()).then_with(|| a.cmp(b))
529}
530
531#[derive(Clone)]
533pub struct Elems<'a> {
534 v: Value<'a>,
535 i: usize,
536}
537
538impl<'a> Iterator for Elems<'a> {
539 type Item = Value<'a>;
540
541 fn next(&mut self) -> Option<Value<'a>> {
542 let out = self.v.at(self.i)?;
543 self.i += 1;
544 Some(out)
545 }
546
547 fn size_hint(&self) -> (usize, Option<usize>) {
548 let left = self.v.len().saturating_sub(self.i);
549 (left, Some(left))
550 }
551}
552
553#[derive(Clone)]
555pub struct Members<'a> {
556 v: Value<'a>,
557 i: usize,
558}
559
560impl<'a> Iterator for Members<'a> {
561 type Item = (&'a [u8], Value<'a>);
562
563 fn next(&mut self) -> Option<(&'a [u8], Value<'a>)> {
564 let key = self.v.key_at(self.i)?;
565 let val = self.v.at(self.i)?;
566 self.i += 1;
567 Some((key, val))
568 }
569
570 fn size_hint(&self) -> (usize, Option<usize>) {
571 let left = self.v.len().saturating_sub(self.i);
572 (left, Some(left))
573 }
574}
575
576#[cfg(test)]
577mod tests {
578 use super::*;
579 use crate::Builder;
580 use yo_common::Rng;
581
582 fn sample() -> Vec<u8> {
584 let mut b = Builder::new();
585 b.begin_object().expect("open");
586 for (k, write) in [
587 ("nil", 0),
588 ("yes", 1),
589 ("n", 2),
590 ("big", 3),
591 ("f", 4),
592 ("s", 5),
593 ("arr", 6),
594 ("obj", 7),
595 ] {
596 b.key(k.as_bytes()).expect("key");
597 match write {
598 0 => b.null().expect("value"),
599 1 => b.bool(true).expect("value"),
600 2 => b.int(-3).expect("value"),
601 3 => b.int(i64::MAX).expect("value"),
602 4 => b.float(0.125).expect("value"),
603 5 => b.text("a string with some length to it").expect("value"),
604 6 => {
605 b.begin_array().expect("open");
606 b.int(1).expect("value");
607 b.text("two").expect("value");
608 b.end_array().expect("close");
609 }
610 _ => {
611 b.begin_object().expect("open");
612 b.key(b"deep").expect("key");
613 b.int(9).expect("value");
614 b.end_object().expect("close");
615 }
616 }
617 }
618 b.end_object().expect("close");
619 b.finish().expect("finished").to_vec()
620 }
621
622 fn walk(bytes: &[u8]) {
629 fn go(v: Value<'_>, depth: usize) {
630 if depth > 8 {
631 return;
632 }
633 let _ = v.kind();
634 let _ = v.is_null();
635 let _ = v.as_bool();
636 let _ = v.as_int();
637 let _ = v.as_float();
638 let _ = v.as_text();
639 let _ = v.text_bytes();
640 let _ = v.is_empty();
641 let _ = v.encoded_len();
642 let _ = v.as_bytes();
643 let _ = v.get(b"nil");
644 let _ = v.get_id(3);
645 let _ = v.path("$.a.b[0]");
646 let _ = format!("{v:?}");
647 for i in 0..v.len().min(16) {
648 let _ = v.key_at(i);
649 let _ = v.key_id_at(i);
650 if let Some(child) = v.at(i) {
651 go(child, depth + 1);
652 }
653 }
654 }
655 if let Some(v) = Value::new(bytes) {
656 let _ = v.validate();
657 go(v, 0);
658 }
659 }
660
661 #[test]
668 fn a_document_cut_short_anywhere_is_refused_and_never_panics() {
669 let bytes = sample();
670 for n in 0..bytes.len() {
671 let cut = &bytes[..n];
672 walk(cut);
673 if let Some(v) = Value::new(cut) {
674 assert!(!v.validate(), "a document missing its tail is not sound");
675 }
676 }
677 assert!(Value::new(&bytes).expect("readable").validate());
678 }
679
680 #[test]
681 fn a_document_with_a_byte_changed_is_never_worse_than_wrong() {
682 let bytes = sample();
683 let mut rng = Rng::new(0x5eed_0d0c);
684 let rounds = if cfg!(miri) { 32 } else { 20_000 };
693 for _ in 0..rounds {
694 let mut damaged = bytes.clone();
695 let at = rng.below(damaged.len());
696 damaged[at] ^= 1 << rng.below(8);
697 walk(&damaged);
698 }
699 }
700
701 #[test]
702 fn a_child_that_points_at_its_own_parent_is_refused() {
703 let mut bytes = sample();
704 let v = Value::new(&bytes).expect("readable");
705 assert!(v.validate());
706 let n = v.len();
709 let entry = 4 + n * 4 + 4;
710 bytes[entry..entry + 4].copy_from_slice(&0u32.to_le_bytes());
711 let v = Value::new(&bytes).expect("the header is still fine");
712 assert!(v.at(0).is_none(), "the child is not readable");
713 assert!(!v.validate());
714 walk(&bytes);
715 }
716
717 #[test]
718 fn a_container_that_claims_more_elements_than_it_has_is_refused() {
719 let bytes = sample();
720 let mut damaged = bytes.clone();
721 let h = u32::from_le_bytes(damaged[..4].try_into().expect("four bytes"));
722 let bigger = (h & 0xff) | ((1u32 << 20) << 8);
723 damaged[..4].copy_from_slice(&bigger.to_le_bytes());
724 assert!(
725 Value::new(&damaged).is_none(),
726 "the entry table would not fit, so the value is not readable at all"
727 );
728 walk(&damaged);
729 }
730
731 #[test]
732 fn keys_sort_by_length_and_then_by_bytes() {
733 let mut keys: Vec<&[u8]> = vec![b"bb", b"a", b"", b"ab", b"z", b"aaa"];
734 keys.sort_by(|a, b| key_order(a, b));
735 assert_eq!(keys, [&b""[..], b"a", b"z", b"ab", b"bb", b"aaa"]);
736 }
737
738 #[test]
739 fn a_document_prints_as_itself() {
740 let bytes = sample();
741 let v = Value::new(&bytes).expect("readable");
742 let text = format!("{v:?}");
743 assert!(text.contains("\"n\": -3"), "{text}");
744 assert!(text.contains("\"arr\": [1, \"two\"]"), "{text}");
745 assert!(text.contains("\"nil\": null"), "{text}");
746 }
747
748 #[test]
749 fn an_unsorted_object_is_still_readable() {
750 let mut bytes = sample();
754 let h = u32::from_le_bytes(bytes[..4].try_into().expect("four bytes"));
755 bytes[..4].copy_from_slice(&(h & !SORTED).to_le_bytes());
756 let v = Value::new(&bytes).expect("readable");
757 assert!(v.validate(), "clearing the claim does not make it unsound");
758 assert_eq!(v.get(b"n").expect("found by scan").as_int(), Some(-3));
759 assert!(v.get(b"missing").is_none());
760 }
761}