1use std::str;
26
27use snafu::prelude::*;
28
29#[derive(Debug, Snafu)]
35#[snafu(visibility(pub(crate)))]
36pub enum Error {
37 #[snafu(display("tape position {pos} out of bounds (len={len})"))]
39 OutOfBounds { pos: usize, len: usize },
40
41 #[snafu(display("unknown tape type byte 0x{tag:02X} at position {pos}"))]
43 UnknownTapeType { tag: u8, pos: usize },
44
45 #[snafu(display("unexpected tape type 0x{found:02X} at position {pos}"))]
49 UnexpectedTapeType { found: u8, pos: usize },
50
51 #[snafu(display("string at offset {offset} out of bounds (string_buf len={len})"))]
53 StringOutOfBounds { offset: usize, len: usize },
54
55 #[snafu(display("value word missing for tape node at position {pos}"))]
57 MissingValueWord { pos: usize },
58
59 #[snafu(display("invalid UTF-8 in string at offset {pos}"))]
61 InvalidUtf8 {
62 source: std::str::Utf8Error,
63 pos: usize,
64 },
65}
66
67pub type Result<T, E = Error> = std::result::Result<T, E>;
68
69const PAYLOAD_MASK: u64 = 0x00FF_FFFF_FFFF_FFFF;
71
72#[derive(Debug, Clone, Copy, PartialEq, Eq)]
74#[repr(u8)]
75pub enum TapeType {
76 Root = b'r',
77 StartObject = b'{',
78 EndObject = b'}',
79 StartArray = b'[',
80 EndArray = b']',
81 String = b'"',
82 Int64 = b'l',
83 Uint64 = b'u',
84 Double = b'd',
85 True = b't',
86 False = b'f',
87 Null = b'n',
88}
89
90impl TapeType {
91 #[inline]
93 pub fn from_tape_word(word: u64) -> Option<Self> {
94 let tag = (word >> 56) as u8;
95 match tag {
96 b'r' => Some(Self::Root),
97 b'{' => Some(Self::StartObject),
98 b'}' => Some(Self::EndObject),
99 b'[' => Some(Self::StartArray),
100 b']' => Some(Self::EndArray),
101 b'"' => Some(Self::String),
102 b'l' => Some(Self::Int64),
103 b'u' => Some(Self::Uint64),
104 b'd' => Some(Self::Double),
105 b't' => Some(Self::True),
106 b'f' => Some(Self::False),
107 b'n' => Some(Self::Null),
108 _ => None,
109 }
110 }
111}
112#[derive(Debug, Clone, PartialEq)]
114#[cfg_attr(feature = "serde", derive(serde::Serialize))]
115pub enum Value<'a> {
116 Null,
117 Bool(bool),
118 Int64(i64),
119 Uint64(u64),
120 Double(f64),
121 String(&'a str),
122 Array(Vec<Value<'a>>),
123 Object(Vec<(&'a str, Value<'a>)>),
124}
125
126impl<'a> Value<'a> {
127 pub fn get(&self, key: &str) -> Option<&Value<'a>> {
129 match self {
130 Value::Object(fields) => fields.iter().find(|(k, _)| *k == key).map(|(_, v)| v),
131 _ => None,
132 }
133 }
134
135 pub fn get_index(&self, index: usize) -> Option<&Value<'a>> {
137 match self {
138 Value::Array(arr) => arr.get(index),
139 _ => None,
140 }
141 }
142
143 pub fn is_null(&self) -> bool {
145 matches!(self, Value::Null)
146 }
147
148 pub fn as_bool(&self) -> Option<bool> {
150 match self {
151 Value::Bool(b) => Some(*b),
152 _ => None,
153 }
154 }
155
156 pub fn as_i64(&self) -> Option<i64> {
158 match self {
159 Value::Int64(i) => Some(*i),
160 Value::Uint64(u) => (*u).try_into().ok(),
161 _ => None,
162 }
163 }
164
165 pub fn as_u64(&self) -> Option<u64> {
167 match self {
168 Value::Uint64(u) => Some(*u),
169 Value::Int64(i) => (*i).try_into().ok(),
170 _ => None,
171 }
172 }
173
174 pub fn as_f64(&self) -> Option<f64> {
176 match self {
177 Value::Double(f) => Some(*f),
178 _ => None,
179 }
180 }
181
182 pub fn as_str(&self) -> Option<&'a str> {
184 match self {
185 Value::String(s) => Some(*s),
186 _ => None,
187 }
188 }
189
190 pub fn as_array(&self) -> Option<&[Value<'a>]> {
192 match self {
193 Value::Array(arr) => Some(arr),
194 _ => None,
195 }
196 }
197
198 pub fn as_object(&self) -> Option<&[(&'a str, Value<'a>)]> {
200 match self {
201 Value::Object(obj) => Some(obj),
202 _ => None,
203 }
204 }
205}
206
207#[derive(Debug, Clone, Copy)]
216pub struct TapeRef<'a> {
217 pub(crate) tape: &'a [u64],
218 pub(crate) string_buf: &'a [u8],
219 pub(crate) pos: usize,
221}
222
223impl<'a> TapeRef<'a> {
224 pub fn new(tape: &'a [u64], string_buf: &'a [u8]) -> Self {
226 Self {
227 tape,
228 string_buf,
229 pos: 0,
230 }
231 }
232
233 #[inline]
235 pub fn pos(&self) -> usize {
236 self.pos
237 }
238
239 #[inline]
241 pub(crate) fn current_word(&self) -> u64 {
242 self.tape[self.pos]
243 }
244
245 #[inline]
247 pub fn current_word_public(&self) -> u64 {
248 self.current_word()
249 }
250
251 #[inline]
253 pub fn tape_type(&self) -> Option<TapeType> {
254 if self.pos >= self.tape.len() {
255 return None;
256 }
257 TapeType::from_tape_word(self.current_word())
258 }
259
260 #[inline]
262 pub(crate) fn payload(&self) -> u64 {
263 self.current_word() & PAYLOAD_MASK
264 }
265
266 #[inline]
268 pub fn payload_public(&self) -> u64 {
269 self.payload()
270 }
271
272 #[inline]
281 pub fn scope_close_idx(&self) -> usize {
282 let next_sibling = (self.payload() & 0x00FF_FFFFFF) as usize;
284 next_sibling.saturating_sub(1)
286 }
287
288 #[inline]
294 pub fn scope_count(&self) -> usize {
295 ((self.current_word() >> 32) & 0x00FF_FFFF) as usize
296 }
297
298 #[inline]
300 pub fn skip(&mut self, n: usize) {
301 self.pos += n;
302 }
303
304 #[inline]
306 pub fn seek_public(&mut self, pos: usize) {
307 self.pos = pos;
308 }
309
310 #[inline]
319 pub fn get_string(&self) -> Result<&'a str> {
320 let word = *self.tape.get(self.pos).context(OutOfBoundsSnafu {
321 pos: self.pos,
322 len: self.tape.len(),
323 })?;
324 let tag = (word >> 56) as u8;
325 ensure!(
326 tag == b'"',
327 UnexpectedTapeTypeSnafu {
328 found: tag,
329 pos: self.pos
330 }
331 );
332 let offset = (word & PAYLOAD_MASK) as usize;
333 let bounds = || StringOutOfBoundsSnafu {
334 offset,
335 len: self.string_buf.len(),
336 };
337 let start = offset.checked_add(4).context(bounds())?;
338 let header = self.string_buf.get(offset..start).context(bounds())?;
339 let len = u32::from_ne_bytes(header.try_into().unwrap()) as usize;
340 let end = start.checked_add(len).context(bounds())?;
341 let bytes = self.string_buf.get(start..end).context(bounds())?;
342 str::from_utf8(bytes).context(InvalidUtf8Snafu { pos: offset })
343 }
344
345 #[inline]
350 pub fn get_int64(&self) -> Result<i64> {
351 debug_assert_eq!(
352 self.tape_type(),
353 Some(TapeType::Int64),
354 "get_int64 called on non-int64 node"
355 );
356 let next = self.pos + 1;
357 ensure!(
358 next < self.tape.len(),
359 MissingValueWordSnafu { pos: self.pos }
360 );
361 Ok(self.tape[next] as i64)
362 }
363
364 #[inline]
366 pub fn get_uint64(&self) -> Result<u64> {
367 debug_assert_eq!(
368 self.tape_type(),
369 Some(TapeType::Uint64),
370 "get_uint64 called on non-uint64 node"
371 );
372 let next = self.pos + 1;
373 ensure!(
374 next < self.tape.len(),
375 MissingValueWordSnafu { pos: self.pos }
376 );
377 Ok(self.tape[next])
378 }
379
380 #[inline]
382 pub fn get_double(&self) -> Result<f64> {
383 debug_assert_eq!(
384 self.tape_type(),
385 Some(TapeType::Double),
386 "get_double called on non-double node"
387 );
388 let next = self.pos + 1;
389 ensure!(
390 next < self.tape.len(),
391 MissingValueWordSnafu { pos: self.pos }
392 );
393 Ok(f64::from_bits(self.tape[next]))
394 }
395
396 pub fn parse_value(&mut self) -> Result<Value<'a>> {
401 ensure!(
402 self.pos < self.tape.len(),
403 OutOfBoundsSnafu {
404 pos: self.pos,
405 len: self.tape.len(),
406 }
407 );
408
409 match self.tape_type() {
410 Some(TapeType::Root) => {
411 self.skip(1);
413 self.parse_value()
414 }
415 Some(TapeType::Null) => {
416 self.skip(1);
417 Ok(Value::Null)
418 }
419 Some(TapeType::True) => {
420 self.skip(1);
421 Ok(Value::Bool(true))
422 }
423 Some(TapeType::False) => {
424 self.skip(1);
425 Ok(Value::Bool(false))
426 }
427 Some(TapeType::Int64) => {
428 let v = self.get_int64()?;
429 self.skip(2); Ok(Value::Int64(v))
431 }
432 Some(TapeType::Uint64) => {
433 let v = self.get_uint64()?;
434 self.skip(2);
435 Ok(Value::Uint64(v))
436 }
437 Some(TapeType::Double) => {
438 let v = self.get_double()?;
439 self.skip(2);
440 Ok(Value::Double(v))
441 }
442 Some(TapeType::String) => {
443 let s = self.get_string()?;
444 self.skip(1);
445 Ok(Value::String(s))
446 }
447 Some(TapeType::StartArray) => {
448 let end_idx = self.scope_close_idx();
450 self.skip(1); let mut arr = Vec::new();
452 while self.pos < end_idx {
453 let v = self.parse_value()?;
454 arr.push(v);
455 }
456 self.skip(1);
458 Ok(Value::Array(arr))
459 }
460 Some(TapeType::StartObject) => {
461 let end_idx = self.scope_close_idx();
463 self.skip(1); let mut obj = Vec::new();
465 while self.pos < end_idx {
466 let key = self.get_string()?;
468 self.skip(1); let value = self.parse_value()?;
470 obj.push((key, value));
471 }
472 self.skip(1);
474 Ok(Value::Object(obj))
475 }
476 Some(t) => UnexpectedTapeTypeSnafu {
477 found: t as u8,
478 pos: self.pos,
479 }
480 .fail(),
481 None => UnknownTapeTypeSnafu {
482 tag: (self.current_word() >> 56) as u8,
483 pos: self.pos,
484 }
485 .fail(),
486 }
487 }
488
489 pub fn visit<V: TapeVisitor<'a>>(&mut self, visitor: &mut V) -> Result<V::Output> {
494 ensure!(
495 self.pos < self.tape.len(),
496 OutOfBoundsSnafu {
497 pos: self.pos,
498 len: self.tape.len(),
499 }
500 );
501
502 match self.tape_type() {
503 Some(TapeType::Root) => {
504 self.skip(1);
505 self.visit(visitor)
506 }
507 Some(TapeType::Null) => {
508 self.skip(1);
509 visitor.visit_null()
510 }
511 Some(TapeType::True) => {
512 self.skip(1);
513 visitor.visit_bool(true)
514 }
515 Some(TapeType::False) => {
516 self.skip(1);
517 visitor.visit_bool(false)
518 }
519 Some(TapeType::Int64) => {
520 let v = self.get_int64()?;
521 self.skip(2);
522 visitor.visit_i64(v)
523 }
524 Some(TapeType::Uint64) => {
525 let v = self.get_uint64()?;
526 self.skip(2);
527 visitor.visit_u64(v)
528 }
529 Some(TapeType::Double) => {
530 let v = self.get_double()?;
531 self.skip(2);
532 visitor.visit_f64(v)
533 }
534 Some(TapeType::String) => {
535 let s = self.get_string()?;
536 self.skip(1);
537 visitor.visit_str(s)
538 }
539 Some(TapeType::StartArray) => {
540 let end_idx = self.scope_close_idx();
541 self.skip(1);
542 let result = visitor.visit_array(self, end_idx)?;
543 self.skip(1); Ok(result)
545 }
546 Some(TapeType::StartObject) => {
547 let end_idx = self.scope_close_idx();
548 self.skip(1);
549 let result = visitor.visit_object(self, end_idx)?;
550 self.skip(1); Ok(result)
552 }
553 Some(t) => UnexpectedTapeTypeSnafu {
554 found: t as u8,
555 pos: self.pos,
556 }
557 .fail(),
558 None => UnknownTapeTypeSnafu {
559 tag: (self.current_word() >> 56) as u8,
560 pos: self.pos,
561 }
562 .fail(),
563 }
564 }
565}
566
567pub trait TapeVisitor<'a> {
572 type Output;
574
575 fn visit_null(&mut self) -> Result<Self::Output>;
576 fn visit_bool(&mut self, v: bool) -> Result<Self::Output>;
577 fn visit_i64(&mut self, v: i64) -> Result<Self::Output>;
578 fn visit_u64(&mut self, v: u64) -> Result<Self::Output>;
579 fn visit_f64(&mut self, v: f64) -> Result<Self::Output>;
580
581 fn visit_str(&mut self, s: &'a str) -> Result<Self::Output>;
583
584 fn visit_array(&mut self, tape: &mut TapeRef<'a>, end_idx: usize) -> Result<Self::Output>;
587
588 fn visit_object(&mut self, tape: &mut TapeRef<'a>, end_idx: usize) -> Result<Self::Output>;
592}
593
594#[cfg(test)]
595mod tests {
596 use super::*;
597
598 #[test]
599 fn tape_type_decoding() {
600 let words: &[u64] = &[
601 (b'r' as u64) << 56 | 3,
602 (b'n' as u64) << 56,
603 (b'r' as u64) << 56,
604 ];
605 let mut r = TapeRef::new(words, &[]);
606 assert_eq!(r.tape_type(), Some(TapeType::Root));
607 r.skip(1);
608 assert_eq!(r.tape_type(), Some(TapeType::Null));
609 }
610
611 #[test]
612 fn tape_bool_types() {
613 let words: &[u64] = &[(b't' as u64) << 56, (b'f' as u64) << 56];
614 let r = TapeRef::new(words, &[]);
615 assert_eq!(r.tape_type(), Some(TapeType::True));
616 let mut r2 = r;
617 r2.skip(1);
618 assert_eq!(r2.tape_type(), Some(TapeType::False));
619 }
620
621 #[test]
622 fn tape_type_from_tape_word() {
623 assert_eq!(
624 TapeType::from_tape_word((b'r' as u64) << 56),
625 Some(TapeType::Root)
626 );
627 assert_eq!(
628 TapeType::from_tape_word((b'{' as u64) << 56),
629 Some(TapeType::StartObject)
630 );
631 assert_eq!(
632 TapeType::from_tape_word((b'}' as u64) << 56),
633 Some(TapeType::EndObject)
634 );
635 assert_eq!(
636 TapeType::from_tape_word((b'[' as u64) << 56),
637 Some(TapeType::StartArray)
638 );
639 assert_eq!(
640 TapeType::from_tape_word((b']' as u64) << 56),
641 Some(TapeType::EndArray)
642 );
643 assert_eq!(
644 TapeType::from_tape_word((b'"' as u64) << 56),
645 Some(TapeType::String)
646 );
647 assert_eq!(
648 TapeType::from_tape_word((b'l' as u64) << 56),
649 Some(TapeType::Int64)
650 );
651 assert_eq!(
652 TapeType::from_tape_word((b'u' as u64) << 56),
653 Some(TapeType::Uint64)
654 );
655 assert_eq!(
656 TapeType::from_tape_word((b'd' as u64) << 56),
657 Some(TapeType::Double)
658 );
659 assert_eq!(
660 TapeType::from_tape_word((b't' as u64) << 56),
661 Some(TapeType::True)
662 );
663 assert_eq!(
664 TapeType::from_tape_word((b'f' as u64) << 56),
665 Some(TapeType::False)
666 );
667 assert_eq!(
668 TapeType::from_tape_word((b'n' as u64) << 56),
669 Some(TapeType::Null)
670 );
671 assert_eq!(TapeType::from_tape_word(0xAA00_0000_0000_0000), None);
672 }
673
674 #[cfg(feature = "serde")]
676 struct NodeCounter {
677 count: usize,
678 }
679
680 #[cfg(feature = "serde")]
681 impl<'a> TapeVisitor<'a> for NodeCounter {
682 type Output = usize;
683
684 fn visit_null(&mut self) -> Result<usize> {
685 self.count += 1;
686 Ok(self.count)
687 }
688
689 fn visit_bool(&mut self, _v: bool) -> Result<usize> {
690 self.count += 1;
691 Ok(self.count)
692 }
693
694 fn visit_i64(&mut self, _v: i64) -> Result<usize> {
695 self.count += 1;
696 Ok(self.count)
697 }
698
699 fn visit_u64(&mut self, _v: u64) -> Result<usize> {
700 self.count += 1;
701 Ok(self.count)
702 }
703
704 fn visit_f64(&mut self, _v: f64) -> Result<usize> {
705 self.count += 1;
706 Ok(self.count)
707 }
708
709 fn visit_str(&mut self, _s: &'a str) -> Result<usize> {
710 self.count += 1;
711 Ok(self.count)
712 }
713
714 fn visit_array(&mut self, tape: &mut TapeRef<'a>, end_idx: usize) -> Result<usize> {
715 while tape.pos() < end_idx {
716 tape.visit(self)?;
717 }
718 Ok(self.count)
719 }
720
721 fn visit_object(&mut self, tape: &mut TapeRef<'a>, end_idx: usize) -> Result<usize> {
722 while tape.pos() < end_idx {
723 tape.visit(self)?;
725 tape.visit(self)?;
727 }
728 Ok(self.count)
729 }
730 }
731
732 #[cfg(feature = "serde")]
733 #[test]
734 fn tape_visitor_counts_nodes() {
735 use crate::dom::Parser;
736 let mut p = Parser::default();
737 let mut tape = p.parse_str(r#"{"a":1,"b":[true,false]}"#).unwrap();
739 let mut counter = NodeCounter { count: 0 };
740 tape.visit(&mut counter).unwrap();
741 assert_eq!(counter.count, 5);
742 }
743
744 #[test]
745 fn parse_value_empty_array() {
746 use crate::dom::Parser;
747 let mut p = Parser::default();
748 let mut tape = p.parse_str("[]").unwrap();
749 let v = tape.parse_value().unwrap();
750 assert_eq!(v, Value::Array(vec![]));
751 }
752
753 #[test]
754 fn parse_value_empty_object() {
755 use crate::dom::Parser;
756 let mut p = Parser::default();
757 let mut tape = p.parse_str("{}").unwrap();
758 let v = tape.parse_value().unwrap();
759 assert_eq!(v, Value::Object(vec![]));
760 }
761
762 #[test]
763 fn parse_value_uint64() {
764 use crate::dom::Parser;
765 let mut p = Parser::default();
766 let mut tape = p.parse_str("18446744073709551615").unwrap(); let v = tape.parse_value().unwrap();
769 assert_eq!(v.as_u64(), Some(u64::MAX));
770 }
771}