1pub mod json_ref;
2
3use crate::sax::Sax;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14#[repr(u8)]
15pub enum DomEntryKind {
16 Null = 0,
17 Bool = 1,
18 Number = 2,
19 String = 3,
20 EscapedString = 4,
21 Key = 5,
22 EscapedKey = 6,
23 StartObject = 7,
24 EndObject = 8,
25 StartArray = 9,
26 EndArray = 10,
27}
28
29const KIND_SHIFT: u64 = 60;
31const PAYLOAD_MASK: u64 = u64::MAX >> 4; #[repr(C)]
54pub struct DomEntry<'a> {
55 pub(crate) tag_payload: u64,
57 pub(crate) ptr: *const u8,
59 _marker: std::marker::PhantomData<&'a str>,
60}
61
62unsafe impl<'a> Send for DomEntry<'a> {}
66unsafe impl<'a> Sync for DomEntry<'a> {}
67
68impl<'a> Drop for DomEntry<'a> {
69 fn drop(&mut self) {
70 let kind = self.kind();
71 if kind == DomEntryKind::EscapedString || kind == DomEntryKind::EscapedKey {
72 if !self.ptr.is_null() {
73 let len = self.payload() as usize;
74 unsafe {
76 let slice = std::slice::from_raw_parts_mut(self.ptr as *mut u8, len);
77 drop(Box::from_raw(slice as *mut [u8] as *mut str));
78 }
79 }
80 }
81 }
82}
83
84impl<'a> Clone for DomEntry<'a> {
85 fn clone(&self) -> Self {
86 let kind = self.kind();
87 if kind == DomEntryKind::EscapedString || kind == DomEntryKind::EscapedKey {
88 let s = self.as_escaped_str_unchecked();
90 let boxed: Box<str> = s.into();
91 let len = boxed.len() as u64;
92 let ptr = Box::into_raw(boxed) as *mut u8 as *const u8;
93 Self {
94 tag_payload: ((kind as u64) << KIND_SHIFT) | (len & PAYLOAD_MASK),
95 ptr,
96 _marker: std::marker::PhantomData,
97 }
98 } else {
99 Self {
100 tag_payload: self.tag_payload,
101 ptr: self.ptr,
102 _marker: std::marker::PhantomData,
103 }
104 }
105 }
106}
107
108impl<'a> std::fmt::Debug for DomEntry<'a> {
110 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
111 match self.kind() {
112 DomEntryKind::Null => write!(f, "Null"),
113 DomEntryKind::Bool => write!(f, "Bool({})", self.payload() != 0),
114 DomEntryKind::Number => write!(f, "Number({:?})", self.as_str_unchecked()),
115 DomEntryKind::String => write!(f, "String({:?})", self.as_str_unchecked()),
116 DomEntryKind::EscapedString => {
117 write!(f, "EscapedString({:?})", self.as_escaped_str_unchecked())
118 }
119 DomEntryKind::Key => write!(f, "Key({:?})", self.as_str_unchecked()),
120 DomEntryKind::EscapedKey => {
121 write!(f, "EscapedKey({:?})", self.as_escaped_str_unchecked())
122 }
123 DomEntryKind::StartObject => write!(f, "StartObject({})", self.payload()),
124 DomEntryKind::EndObject => write!(f, "EndObject"),
125 DomEntryKind::StartArray => write!(f, "StartArray({})", self.payload()),
126 DomEntryKind::EndArray => write!(f, "EndArray"),
127 }
128 }
129}
130
131impl<'a> PartialEq for DomEntry<'a> {
133 fn eq(&self, other: &Self) -> bool {
134 if self.kind() != other.kind() {
135 return false;
136 }
137 match self.kind() {
138 DomEntryKind::Null | DomEntryKind::EndObject | DomEntryKind::EndArray => true,
139 DomEntryKind::Bool => self.payload() == other.payload(),
140 DomEntryKind::StartObject | DomEntryKind::StartArray => {
141 self.payload() == other.payload()
142 }
143 DomEntryKind::Number | DomEntryKind::String | DomEntryKind::Key => {
144 self.as_str_unchecked() == other.as_str_unchecked()
145 }
146 DomEntryKind::EscapedString | DomEntryKind::EscapedKey => {
147 self.as_escaped_str_unchecked() == other.as_escaped_str_unchecked()
148 }
149 }
150 }
151}
152
153impl<'a> DomEntry<'a> {
158 #[inline]
161 fn make(kind: DomEntryKind, payload: u64, ptr: *const u8) -> Self {
162 Self {
163 tag_payload: ((kind as u64) << KIND_SHIFT) | (payload & PAYLOAD_MASK),
164 ptr,
165 _marker: std::marker::PhantomData,
166 }
167 }
168
169 #[inline]
171 pub fn kind(&self) -> DomEntryKind {
172 unsafe { std::mem::transmute((self.tag_payload >> KIND_SHIFT) as u8) }
174 }
175
176 #[inline]
178 pub(crate) fn payload(&self) -> u64 {
179 self.tag_payload & PAYLOAD_MASK
180 }
181
182 #[inline]
184 fn as_str_unchecked(&self) -> &'a str {
185 let len = self.payload() as usize;
186 unsafe { std::str::from_utf8_unchecked(std::slice::from_raw_parts(self.ptr, len)) }
187 }
188
189 #[inline]
191 fn as_escaped_str_unchecked(&self) -> &str {
192 let len = self.payload() as usize;
193 unsafe { std::str::from_utf8_unchecked(std::slice::from_raw_parts(self.ptr, len)) }
194 }
195
196 #[inline]
199 pub fn null_entry() -> Self {
200 Self::make(DomEntryKind::Null, 0, std::ptr::null())
201 }
202 #[inline]
203 pub fn bool_entry(v: bool) -> Self {
204 Self::make(DomEntryKind::Bool, v as u64, std::ptr::null())
205 }
206 #[inline]
207 pub fn number_entry(s: &'a str) -> Self {
208 Self::make(DomEntryKind::Number, s.len() as u64, s.as_ptr())
209 }
210 #[inline]
211 pub fn string_entry(s: &'a str) -> Self {
212 Self::make(DomEntryKind::String, s.len() as u64, s.as_ptr())
213 }
214 #[inline]
215 pub fn escaped_string_entry(s: Box<str>) -> Self {
216 let len = s.len() as u64;
217 let ptr = Box::into_raw(s) as *mut u8 as *const u8;
218 Self::make(DomEntryKind::EscapedString, len, ptr)
219 }
220 #[inline]
221 pub fn key_entry(s: &'a str) -> Self {
222 Self::make(DomEntryKind::Key, s.len() as u64, s.as_ptr())
223 }
224 #[inline]
225 pub fn escaped_key_entry(s: Box<str>) -> Self {
226 let len = s.len() as u64;
227 let ptr = Box::into_raw(s) as *mut u8 as *const u8;
228 Self::make(DomEntryKind::EscapedKey, len, ptr)
229 }
230 #[inline]
232 pub fn start_object_entry(end_idx: usize) -> Self {
233 Self::make(DomEntryKind::StartObject, end_idx as u64, std::ptr::null())
234 }
235 #[inline]
236 pub fn end_object_entry() -> Self {
237 Self::make(DomEntryKind::EndObject, 0, std::ptr::null())
238 }
239 #[inline]
241 pub fn start_array_entry(end_idx: usize) -> Self {
242 Self::make(DomEntryKind::StartArray, end_idx as u64, std::ptr::null())
243 }
244 #[inline]
245 pub fn end_array_entry() -> Self {
246 Self::make(DomEntryKind::EndArray, 0, std::ptr::null())
247 }
248
249 #[inline]
253 pub(crate) fn set_payload(&mut self, v: usize) {
254 self.tag_payload = (self.tag_payload & !(PAYLOAD_MASK)) | ((v as u64) & PAYLOAD_MASK);
255 }
256
257 #[inline]
261 pub fn as_start_object(&self) -> Option<usize> {
262 if self.kind() == DomEntryKind::StartObject {
263 Some(self.payload() as usize)
264 } else {
265 None
266 }
267 }
268 #[inline]
270 pub fn as_start_array(&self) -> Option<usize> {
271 if self.kind() == DomEntryKind::StartArray {
272 Some(self.payload() as usize)
273 } else {
274 None
275 }
276 }
277 #[inline]
279 pub fn as_bool(&self) -> Option<bool> {
280 if self.kind() == DomEntryKind::Bool {
281 Some(self.payload() != 0)
282 } else {
283 None
284 }
285 }
286 #[inline]
288 pub fn as_number(&self) -> Option<&'a str> {
289 if self.kind() == DomEntryKind::Number {
290 Some(self.as_str_unchecked())
291 } else {
292 None
293 }
294 }
295 #[inline]
297 pub fn as_string(&self) -> Option<&str> {
298 match self.kind() {
299 DomEntryKind::String => Some(self.as_str_unchecked()),
300 DomEntryKind::EscapedString => Some(self.as_escaped_str_unchecked()),
301 _ => None,
302 }
303 }
304
305 #[cfg(feature = "serde")]
309 #[inline]
310 pub(crate) fn source_string(&self) -> Option<&'a str> {
311 if self.kind() == DomEntryKind::String {
312 Some(self.as_str_unchecked())
313 } else {
314 None
315 }
316 }
317
318 #[inline]
320 pub fn as_key(&self) -> Option<&str> {
321 match self.kind() {
322 DomEntryKind::Key => Some(self.as_str_unchecked()),
323 DomEntryKind::EscapedKey => Some(self.as_escaped_str_unchecked()),
324 _ => None,
325 }
326 }
327}
328
329#[allow(non_snake_case, non_upper_case_globals)]
332impl<'a> DomEntry<'a> {
333 pub const Null: DomEntry<'static> = DomEntry {
335 tag_payload: 0,
336 ptr: std::ptr::null(),
337 _marker: std::marker::PhantomData,
338 };
339 pub const EndObject: DomEntry<'static> = DomEntry {
341 tag_payload: (DomEntryKind::EndObject as u64) << KIND_SHIFT,
342 ptr: std::ptr::null(),
343 _marker: std::marker::PhantomData,
344 };
345 pub const EndArray: DomEntry<'static> = DomEntry {
347 tag_payload: (DomEntryKind::EndArray as u64) << KIND_SHIFT,
348 ptr: std::ptr::null(),
349 _marker: std::marker::PhantomData,
350 };
351
352 #[inline]
354 pub fn Bool(v: bool) -> Self {
355 Self::bool_entry(v)
356 }
357 #[inline]
359 pub fn Number(s: &'a str) -> Self {
360 Self::number_entry(s)
361 }
362 #[inline]
364 pub fn String(s: &'a str) -> Self {
365 Self::string_entry(s)
366 }
367 #[inline]
369 pub fn EscapedString(s: Box<str>) -> Self {
370 Self::escaped_string_entry(s)
371 }
372 #[inline]
374 pub fn Key(s: &'a str) -> Self {
375 Self::key_entry(s)
376 }
377 #[inline]
379 pub fn EscapedKey(s: Box<str>) -> Self {
380 Self::escaped_key_entry(s)
381 }
382 #[inline]
384 pub fn StartObject(end_idx: usize) -> Self {
385 Self::start_object_entry(end_idx)
386 }
387 #[inline]
389 pub fn StartArray(end_idx: usize) -> Self {
390 Self::start_array_entry(end_idx)
391 }
392}
393
394#[derive(Debug)]
405pub struct Dom<'a> {
406 pub entries: Vec<DomEntry<'a>>,
407 pub(crate) has_escapes: bool,
411}
412
413impl<'a> Drop for Dom<'a> {
414 fn drop(&mut self) {
415 if !self.has_escapes {
416 unsafe { self.entries.set_len(0) };
422 }
423 }
425}
426
427pub(crate) struct DomWriter<'a> {
432 entries: Vec<DomEntry<'a>>,
433 open: Vec<usize>,
435 has_escapes: bool,
437}
438
439impl<'a> DomWriter<'a> {
440 pub(crate) fn with_capacity(cap: usize) -> Self {
441 Self {
442 entries: Vec::with_capacity(cap),
443 open: Vec::new(),
444 has_escapes: false,
445 }
446 }
447}
448
449impl<'a> Sax<'a> for DomWriter<'a> {
450 type Output = Dom<'a>;
451
452 fn null(&mut self) {
453 self.entries.push(DomEntry::null_entry());
454 }
455 fn bool_val(&mut self, v: bool) {
456 self.entries.push(DomEntry::bool_entry(v));
457 }
458 fn number(&mut self, s: &'a str) {
459 self.entries.push(DomEntry::number_entry(s));
460 }
461 fn string(&mut self, s: &'a str) {
462 self.entries.push(DomEntry::string_entry(s));
463 }
464 fn escaped_string(&mut self, s: &str) {
465 self.has_escapes = true;
466 let mut buf = String::new();
467 crate::unescape_str(s, &mut buf);
468 self.entries
469 .push(DomEntry::escaped_string_entry(buf.into_boxed_str()));
470 }
471 fn key(&mut self, s: &'a str) {
472 self.entries.push(DomEntry::key_entry(s));
473 }
474 fn escaped_key(&mut self, s: &str) {
475 self.has_escapes = true;
476 let mut buf = String::new();
477 crate::unescape_str(s, &mut buf);
478 self.entries
479 .push(DomEntry::escaped_key_entry(buf.into_boxed_str()));
480 }
481 fn start_object(&mut self) {
482 let idx = self.entries.len();
483 self.open.push(idx);
484 self.entries.push(DomEntry::start_object_entry(0)); }
486 fn end_object(&mut self) {
487 let end_idx = self.entries.len();
488 self.entries.push(DomEntry::end_object_entry());
489 if let Some(start_idx) = self.open.pop() {
490 self.entries[start_idx].set_payload(end_idx);
491 }
492 }
493 fn start_array(&mut self) {
494 let idx = self.entries.len();
495 self.open.push(idx);
496 self.entries.push(DomEntry::start_array_entry(0)); }
498 fn end_array(&mut self) {
499 let end_idx = self.entries.len();
500 self.entries.push(DomEntry::end_array_entry());
501 if let Some(start_idx) = self.open.pop() {
502 self.entries[start_idx].set_payload(end_idx);
503 }
504 }
505 fn finish(self) -> Option<Dom<'a>> {
506 if self.open.is_empty() {
507 Some(Dom {
508 entries: self.entries,
509 has_escapes: self.has_escapes,
510 })
511 } else {
512 None
513 }
514 }
515}
516
517#[derive(Clone, Copy)]
530pub struct DomRef<'t, 'src: 't> {
531 pub(crate) tape: &'t [DomEntry<'src>],
532 pub(crate) pos: usize,
533}
534
535impl<'src> Dom<'src> {
536 pub fn root<'t>(&'t self) -> Option<DomRef<'t, 'src>> {
539 if self.entries.is_empty() {
540 None
541 } else {
542 Some(DomRef {
543 tape: &self.entries,
544 pos: 0,
545 })
546 }
547 }
548}
549
550pub(crate) fn dom_skip(entries: &[DomEntry<'_>], pos: usize) -> usize {
554 let e = &entries[pos];
555 match e.kind() {
556 DomEntryKind::StartObject | DomEntryKind::StartArray => e.payload() as usize + 1,
557 _ => pos + 1,
558 }
559}
560
561pub struct DomObjectIter<'t, 'src: 't> {
570 tape: &'t [DomEntry<'src>],
571 pos: usize,
572 end: usize,
573}
574
575impl<'t, 'src: 't> Iterator for DomObjectIter<'t, 'src> {
576 type Item = (&'t str, DomRef<'t, 'src>);
577
578 fn next(&mut self) -> Option<Self::Item> {
579 if self.pos >= self.end {
580 return None;
581 }
582 let key: &'t str = self.tape[self.pos].as_key()?;
583 let val_pos = self.pos + 1;
584 self.pos = dom_skip(self.tape, val_pos);
585 Some((
586 key,
587 DomRef {
588 tape: self.tape,
589 pos: val_pos,
590 },
591 ))
592 }
593}
594
595pub struct DomArrayIter<'t, 'src: 't> {
600 tape: &'t [DomEntry<'src>],
601 pos: usize,
602 end: usize,
603}
604
605impl<'t, 'src: 't> Iterator for DomArrayIter<'t, 'src> {
606 type Item = DomRef<'t, 'src>;
607
608 fn next(&mut self) -> Option<Self::Item> {
609 if self.pos >= self.end {
610 return None;
611 }
612 let item = DomRef {
613 tape: self.tape,
614 pos: self.pos,
615 };
616 self.pos = dom_skip(self.tape, self.pos);
617 Some(item)
618 }
619}
620
621impl<'t, 'src: 't> DomRef<'t, 'src> {
626 pub fn object_iter(self) -> Option<DomObjectIter<'t, 'src>> {
641 self.tape[self.pos]
642 .as_start_object()
643 .map(|end| DomObjectIter {
644 tape: self.tape,
645 pos: self.pos + 1,
646 end,
647 })
648 }
649
650 pub fn array_iter(self) -> Option<DomArrayIter<'t, 'src>> {
665 self.tape[self.pos]
666 .as_start_array()
667 .map(|end| DomArrayIter {
668 tape: self.tape,
669 pos: self.pos + 1,
670 end,
671 })
672 }
673}
674
675#[cfg(test)]
680mod tests {
681 use crate::{JsonRef, parse_to_dom};
682
683 use super::{Dom, DomEntry};
684
685 fn run_tape(json: &'static str) -> Option<Dom<'static>> {
686 parse_to_dom(json, None)
687 }
688
689 fn te_str(s: &'static str) -> DomEntry<'static> {
690 DomEntry::String(s)
691 }
692 fn te_key(s: &'static str) -> DomEntry<'static> {
693 DomEntry::Key(s)
694 }
695 fn te_num(s: &'static str) -> DomEntry<'static> {
696 DomEntry::Number(s)
697 }
698
699 #[test]
700 fn tape_scalar_values() {
701 assert_eq!(run_tape("null").unwrap().entries, vec![DomEntry::Null]);
702 assert_eq!(
703 run_tape("true").unwrap().entries,
704 vec![DomEntry::Bool(true)]
705 );
706 assert_eq!(
707 run_tape("false").unwrap().entries,
708 vec![DomEntry::Bool(false)]
709 );
710 assert_eq!(run_tape("42").unwrap().entries, vec![te_num("42")]);
711 assert_eq!(run_tape(r#""hi""#).unwrap().entries, vec![te_str("hi")]);
712 }
713
714 #[test]
715 fn tape_empty_object() {
716 let t = run_tape("{}").unwrap();
717 assert_eq!(
719 t.entries,
720 vec![DomEntry::StartObject(1), DomEntry::EndObject]
721 );
722 assert_eq!(t.entries[0], DomEntry::StartObject(1));
724 }
725
726 #[test]
727 fn tape_empty_array() {
728 let t = run_tape("[]").unwrap();
729 assert_eq!(t.entries, vec![DomEntry::StartArray(1), DomEntry::EndArray]);
730 assert_eq!(t.entries[0], DomEntry::StartArray(1));
731 }
732
733 #[test]
734 fn tape_simple_object() {
735 let t = run_tape(r#"{"a":1}"#).unwrap();
737 assert_eq!(
738 t.entries,
739 vec![
740 DomEntry::StartObject(3),
741 te_key("a"),
742 te_num("1"),
743 DomEntry::EndObject,
744 ]
745 );
746 assert_eq!(t.entries[0], DomEntry::StartObject(3));
748 }
749
750 #[test]
751 fn tape_simple_array() {
752 let t = run_tape(r#"[1,2,3]"#).unwrap();
754 assert_eq!(
755 t.entries,
756 vec![
757 DomEntry::StartArray(4),
758 te_num("1"),
759 te_num("2"),
760 te_num("3"),
761 DomEntry::EndArray,
762 ]
763 );
764 }
765
766 #[test]
767 fn tape_nested() {
768 let t = run_tape(r#"{"a":[1,2]}"#).unwrap();
770 assert_eq!(
771 t.entries,
772 vec![
773 DomEntry::StartObject(6), te_key("a"), DomEntry::StartArray(5), te_num("1"), te_num("2"), DomEntry::EndArray, DomEntry::EndObject, ]
781 );
782 assert_eq!(t.entries[0], DomEntry::StartObject(6));
783 assert_eq!(t.entries[2], DomEntry::StartArray(5));
784 }
785
786 #[test]
787 fn tape_multi_key_object() {
788 let t = run_tape(r#"{"x":1,"y":2}"#).unwrap();
789 assert_eq!(
790 t.entries,
791 vec![
792 DomEntry::StartObject(5), te_key("x"), te_num("1"), te_key("y"), te_num("2"), DomEntry::EndObject, ]
799 );
800 assert_eq!(t.entries[0], DomEntry::StartObject(5));
801 }
802
803 #[test]
804 fn tape_invalid_returns_none() {
805 assert!(run_tape("[1,2,]").is_none());
806 assert!(run_tape(r#"{"a":1,}"#).is_none());
807 assert!(run_tape("{bad}").is_none());
808 }
809
810 #[test]
811 fn tape_skip_object() {
812 let t = run_tape(r#"[{"x":1},2]"#).unwrap();
814 assert_eq!(t.entries.len(), 7);
817 let end = t.entries[1]
819 .as_start_object()
820 .expect("expected StartObject at index 1");
821 assert_eq!(end, 4);
822 assert_eq!(t.entries[5], te_num("2"));
824 }
825
826 #[test]
827 fn tape_object_iter() {
828 let t = run_tape(r#"{"x":1,"y":true,"z":"hi"}"#).unwrap();
829 let root = t.root().unwrap();
830 let pairs: Vec<_> = root
831 .object_iter()
832 .expect("should be object")
833 .map(|(k, v)| (k.to_string(), (v.as_number_str(), v.as_bool(), v.as_str())))
834 .collect();
835 assert_eq!(pairs.len(), 3);
836 assert_eq!(pairs[0].0, "x");
837 assert_eq!(pairs[0].1, (Some("1"), None, None));
838 assert_eq!(pairs[1].0, "y");
839 assert_eq!(pairs[1].1, (None, Some(true), None));
840 assert_eq!(pairs[2].0, "z");
841 assert_eq!(pairs[2].1, (None, None, Some("hi")));
842 let at = parse_to_dom("[1]", None).unwrap();
844 assert!(at.root().unwrap().object_iter().is_none());
845 }
846
847 #[test]
848 fn tape_array_iter() {
849 let t = run_tape(r#"[1,"two",false,null]"#).unwrap();
850 let root = t.root().unwrap();
851 let items: Vec<_> = root.array_iter().expect("should be array").collect();
852 assert_eq!(items.len(), 4);
853 assert_eq!(items[0].as_number_str(), Some("1"));
854 assert_eq!(items[1].as_str(), Some("two"));
855 assert_eq!(items[2].as_bool(), Some(false));
856 assert!(items[3].is_null());
857 let nt = run_tape(r#"[[1,2],{"a":3}]"#).unwrap();
859 let nelems: Vec<_> = nt.root().unwrap().array_iter().unwrap().collect();
860 assert_eq!(nelems.len(), 2);
861 assert!(nelems[0].is_array());
862 assert!(nelems[1].is_object());
863 let ot = parse_to_dom(r#"{"a":1}"#, None).unwrap();
865 assert!(ot.root().unwrap().array_iter().is_none());
866 }
867}