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]
301 pub fn as_bytes(&self) -> Option<&'a [u8]> {
302 self.b.get(..self.encoded_len()?)
303 }
304
305 #[must_use]
313 pub fn validate(&self) -> bool {
314 self.validate_at(0)
315 }
316
317 fn validate_at(&self, depth: usize) -> bool {
318 if depth > DEPTH_MAX {
319 return false;
320 }
321 let Some(h) = head::read(self.b, 0) else {
322 return false;
323 };
324 let Some(tag) = Tag::of(h) else {
325 return false;
326 };
327 if !matches!(tag, Tag::Container) {
328 let n = head::count(h);
329 if matches!(tag, Tag::Int) && !matches!(n, 1 | 2 | 4 | 8) {
330 return false;
331 }
332 if matches!(tag, Tag::Float) && n != 8 {
333 return false;
334 }
335 if matches!(tag, Tag::Null | Tag::False | Tag::True) && n != 0 {
336 return false;
337 }
338 return self.b.len() >= 4 + n;
339 }
340 if h & OFFSETS == 0 {
341 return false;
342 }
343 let n = head::count(h);
344 let Some(mut want) = self.entries_end() else {
345 return false;
346 };
347 if self.b.len() < want {
348 return false;
349 }
350 if self.is_object() && !self.is_interned() {
351 for i in 0..n {
354 let (Some(at), Some(end)) = (self.key_off(i), self.key_end(i)) else {
355 return false;
356 };
357 if at != want || end < at || self.b.len() < end {
358 return false;
359 }
360 want = end;
361 }
362 }
363 for i in 0..n {
364 let Some((copy, off)) = self.entry(i) else {
365 return false;
366 };
367 if off != want {
370 return false;
371 }
372 let Some(child) = self.b.get(off..).and_then(Value::new) else {
373 return false;
374 };
375 if child.head() != copy || !child.validate_at(depth + 1) {
376 return false;
377 }
378 let Some(len) = child.encoded_len_at(depth + 1) else {
379 return false;
380 };
381 want = off + len;
382 }
383 if self.is_object() && h & SORTED != 0 && !self.keys_ascend(n) {
384 return false;
385 }
386 true
387 }
388
389 fn head(&self) -> u32 {
391 head::read(self.b, 0).unwrap_or(0)
392 }
393
394 fn tag(&self) -> Tag {
395 Tag::of(self.head()).unwrap_or(Tag::Null)
396 }
397
398 fn is_container(&self) -> bool {
399 matches!(self.tag(), Tag::Container)
400 }
401
402 fn is_object(&self) -> bool {
403 self.is_container() && self.head() & ARRAY == 0
404 }
405
406 fn payload(&self) -> Option<&'a [u8]> {
408 let n = head::count(self.head());
409 self.b.get(4..4 + n)
410 }
411
412 fn entries_at(&self) -> usize {
414 4 + crate::layout::keys_area(self.head(), self.len())
415 }
416
417 fn entries_end(&self) -> Option<usize> {
419 self.entries_at().checked_add(self.len().checked_mul(8)?)
420 }
421
422 fn entry(&self, i: usize) -> Option<(u32, usize)> {
424 if !self.is_container() || i >= self.len() {
425 return None;
426 }
427 let at = self.entries_at() + i * 8;
428 let copy = head::read(self.b, at)?;
429 let off = head::read(self.b, at + 4)? as usize;
430 if off < self.entries_end()? {
435 return None;
436 }
437 Some((copy, off))
438 }
439
440 fn key_off(&self, i: usize) -> Option<usize> {
442 if i >= self.len() {
443 return None;
444 }
445 Some(head::read(self.b, 4 + i * 4)? as usize)
446 }
447
448 fn key_end(&self, i: usize) -> Option<usize> {
454 if i + 1 < self.len() {
455 self.key_off(i + 1)
456 } else {
457 self.entry(0).map(|(_, off)| off)
458 }
459 }
460
461 fn keys_ascend(&self, n: usize) -> bool {
462 for i in 1..n {
463 let ord = if self.is_interned() {
464 match (self.key_id_at(i - 1), self.key_id_at(i)) {
465 (Some(a), Some(b)) => a.cmp(&b),
466 _ => return false,
467 }
468 } else {
469 match (self.key_at(i - 1), self.key_at(i)) {
470 (Some(a), Some(b)) => key_order(a, b),
471 _ => return false,
472 }
473 };
474 if ord != Ordering::Less {
475 return false;
476 }
477 }
478 true
479 }
480}
481
482impl core::fmt::Debug for Value<'_> {
483 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
484 match self.kind() {
485 Kind::Null => f.write_str("null"),
486 Kind::Bool => write!(f, "{}", self.as_bool().unwrap_or(false)),
487 Kind::Int => write!(f, "{}", self.as_int().unwrap_or(0)),
488 Kind::Float => write!(f, "{}", self.as_float().unwrap_or(0.0)),
489 Kind::Text => write!(f, "{:?}", self.as_text().unwrap_or("")),
490 Kind::Array => f.debug_list().entries(self.iter()).finish(),
491 Kind::Object => {
492 let mut m = f.debug_map();
493 for (k, v) in self.members() {
494 m.entry(&String::from_utf8_lossy(k), &v);
495 }
496 m.finish()
497 }
498 }
499 }
500}
501
502#[must_use]
509pub fn key_order(a: &[u8], b: &[u8]) -> Ordering {
510 a.len().cmp(&b.len()).then_with(|| a.cmp(b))
511}
512
513#[derive(Clone)]
515pub struct Elems<'a> {
516 v: Value<'a>,
517 i: usize,
518}
519
520impl<'a> Iterator for Elems<'a> {
521 type Item = Value<'a>;
522
523 fn next(&mut self) -> Option<Value<'a>> {
524 let out = self.v.at(self.i)?;
525 self.i += 1;
526 Some(out)
527 }
528
529 fn size_hint(&self) -> (usize, Option<usize>) {
530 let left = self.v.len().saturating_sub(self.i);
531 (left, Some(left))
532 }
533}
534
535#[derive(Clone)]
537pub struct Members<'a> {
538 v: Value<'a>,
539 i: usize,
540}
541
542impl<'a> Iterator for Members<'a> {
543 type Item = (&'a [u8], Value<'a>);
544
545 fn next(&mut self) -> Option<(&'a [u8], Value<'a>)> {
546 let key = self.v.key_at(self.i)?;
547 let val = self.v.at(self.i)?;
548 self.i += 1;
549 Some((key, val))
550 }
551
552 fn size_hint(&self) -> (usize, Option<usize>) {
553 let left = self.v.len().saturating_sub(self.i);
554 (left, Some(left))
555 }
556}
557
558#[cfg(test)]
559mod tests {
560 use super::*;
561 use crate::Builder;
562 use yo_common::Rng;
563
564 fn sample() -> Vec<u8> {
566 let mut b = Builder::new();
567 b.begin_object().expect("open");
568 for (k, write) in [
569 ("nil", 0),
570 ("yes", 1),
571 ("n", 2),
572 ("big", 3),
573 ("f", 4),
574 ("s", 5),
575 ("arr", 6),
576 ("obj", 7),
577 ] {
578 b.key(k.as_bytes()).expect("key");
579 match write {
580 0 => b.null().expect("value"),
581 1 => b.bool(true).expect("value"),
582 2 => b.int(-3).expect("value"),
583 3 => b.int(i64::MAX).expect("value"),
584 4 => b.float(0.125).expect("value"),
585 5 => b.text("a string with some length to it").expect("value"),
586 6 => {
587 b.begin_array().expect("open");
588 b.int(1).expect("value");
589 b.text("two").expect("value");
590 b.end_array().expect("close");
591 }
592 _ => {
593 b.begin_object().expect("open");
594 b.key(b"deep").expect("key");
595 b.int(9).expect("value");
596 b.end_object().expect("close");
597 }
598 }
599 }
600 b.end_object().expect("close");
601 b.finish().expect("finished").to_vec()
602 }
603
604 fn walk(bytes: &[u8]) {
611 fn go(v: Value<'_>, depth: usize) {
612 if depth > 8 {
613 return;
614 }
615 let _ = v.kind();
616 let _ = v.is_null();
617 let _ = v.as_bool();
618 let _ = v.as_int();
619 let _ = v.as_float();
620 let _ = v.as_text();
621 let _ = v.text_bytes();
622 let _ = v.is_empty();
623 let _ = v.encoded_len();
624 let _ = v.as_bytes();
625 let _ = v.get(b"nil");
626 let _ = v.get_id(3);
627 let _ = v.path("$.a.b[0]");
628 let _ = format!("{v:?}");
629 for i in 0..v.len().min(16) {
630 let _ = v.key_at(i);
631 let _ = v.key_id_at(i);
632 if let Some(child) = v.at(i) {
633 go(child, depth + 1);
634 }
635 }
636 }
637 if let Some(v) = Value::new(bytes) {
638 let _ = v.validate();
639 go(v, 0);
640 }
641 }
642
643 #[test]
644 fn a_document_cut_short_anywhere_is_refused_and_never_panics() {
645 let bytes = sample();
646 for n in 0..bytes.len() {
647 let cut = &bytes[..n];
648 walk(cut);
649 if let Some(v) = Value::new(cut) {
650 assert!(!v.validate(), "a document missing its tail is not sound");
651 }
652 }
653 assert!(Value::new(&bytes).expect("readable").validate());
654 }
655
656 #[test]
657 fn a_document_with_a_byte_changed_is_never_worse_than_wrong() {
658 let bytes = sample();
659 let mut rng = Rng::new(0x5eed_0d0c);
660 for _ in 0..20_000 {
661 let mut damaged = bytes.clone();
662 let at = rng.below(damaged.len());
663 damaged[at] ^= 1 << rng.below(8);
664 walk(&damaged);
665 }
666 }
667
668 #[test]
669 fn a_child_that_points_at_its_own_parent_is_refused() {
670 let mut bytes = sample();
671 let v = Value::new(&bytes).expect("readable");
672 assert!(v.validate());
673 let n = v.len();
676 let entry = 4 + n * 4 + 4;
677 bytes[entry..entry + 4].copy_from_slice(&0u32.to_le_bytes());
678 let v = Value::new(&bytes).expect("the header is still fine");
679 assert!(v.at(0).is_none(), "the child is not readable");
680 assert!(!v.validate());
681 walk(&bytes);
682 }
683
684 #[test]
685 fn a_container_that_claims_more_elements_than_it_has_is_refused() {
686 let bytes = sample();
687 let mut damaged = bytes.clone();
688 let h = u32::from_le_bytes(damaged[..4].try_into().expect("four bytes"));
689 let bigger = (h & 0xff) | ((1u32 << 20) << 8);
690 damaged[..4].copy_from_slice(&bigger.to_le_bytes());
691 assert!(
692 Value::new(&damaged).is_none(),
693 "the entry table would not fit, so the value is not readable at all"
694 );
695 walk(&damaged);
696 }
697
698 #[test]
699 fn keys_sort_by_length_and_then_by_bytes() {
700 let mut keys: Vec<&[u8]> = vec![b"bb", b"a", b"", b"ab", b"z", b"aaa"];
701 keys.sort_by(|a, b| key_order(a, b));
702 assert_eq!(keys, [&b""[..], b"a", b"z", b"ab", b"bb", b"aaa"]);
703 }
704
705 #[test]
706 fn a_document_prints_as_itself() {
707 let bytes = sample();
708 let v = Value::new(&bytes).expect("readable");
709 let text = format!("{v:?}");
710 assert!(text.contains("\"n\": -3"), "{text}");
711 assert!(text.contains("\"arr\": [1, \"two\"]"), "{text}");
712 assert!(text.contains("\"nil\": null"), "{text}");
713 }
714
715 #[test]
716 fn an_unsorted_object_is_still_readable() {
717 let mut bytes = sample();
721 let h = u32::from_le_bytes(bytes[..4].try_into().expect("four bytes"));
722 bytes[..4].copy_from_slice(&(h & !SORTED).to_le_bytes());
723 let v = Value::new(&bytes).expect("readable");
724 assert!(v.validate(), "clearing the claim does not make it unsound");
725 assert_eq!(v.get(b"n").expect("found by scan").as_int(), Some(-3));
726 assert!(v.get(b"missing").is_none());
727 }
728}