1use ahash::{AHashMap, AHashSet};
8use fionn_core::{DsonError, Result};
9pub use fionn_core::{ParsedPath, PathComponent, PathComponentRef};
10use simd_json::value::tape::{Node, Tape};
11
12type FastHashMap<K, V> = AHashMap<K, V>;
14type FastHashSet<T> = AHashSet<T>;
15
16#[inline]
23fn escape_json_string(s: &str, output: &mut String) {
24 use std::fmt::Write;
25 for c in s.chars() {
26 match c {
27 '"' => output.push_str("\\\""),
28 '\\' => output.push_str("\\\\"),
29 '\n' => output.push_str("\\n"),
30 '\r' => output.push_str("\\r"),
31 '\t' => output.push_str("\\t"),
32 c if c.is_control() => {
34 let _ = write!(output, "\\u{:04x}", c as u32);
35 }
36 c => output.push(c),
37 }
38 }
39}
40
41#[derive(Debug, Clone)]
43pub enum SimdValue {
44 String(String),
46 Null,
48 Bool(bool),
50 Number(String),
52}
53
54pub struct DsonTape {
56 tape: Tape<'static>,
57 data: Vec<u8>, }
59
60impl DsonTape {
61 pub fn parse(json: &str) -> Result<Self> {
66 let mut bytes = json.as_bytes().to_vec();
68 let tape = unsafe {
69 std::mem::transmute::<Tape<'_>, Tape<'static>>(
71 simd_json::to_tape(&mut bytes)
72 .map_err(|e| DsonError::ParseError(format!("SIMD-JSON parse error: {e}")))?,
73 )
74 };
75
76 Ok(Self { tape, data: bytes })
77 }
78
79 #[must_use]
81 pub const fn tape(&self) -> &Tape<'static> {
82 &self.tape
83 }
84
85 #[must_use]
87 #[inline]
88 pub fn nodes(&self) -> &[Node<'static>] {
89 &self.tape.0
90 }
91
92 #[must_use]
94 #[inline]
95 pub fn root(&self) -> Node<'static> {
96 self.nodes()[0]
97 }
98
99 pub fn skip_field(&self, current_index: usize) -> Result<Option<usize>> {
104 let nodes = self.nodes();
105 if current_index >= nodes.len() {
106 return Ok(None);
107 }
108
109 let mut index = current_index;
112
113 if let Node::String(_) = &nodes[index] {
115 index += 1; }
117
118 index = self.skip_value(index)?;
120
121 Ok(Some(index))
122 }
123
124 pub fn skip_value(&self, start_index: usize) -> Result<usize> {
129 let nodes = self.nodes();
130 if start_index >= nodes.len() {
131 return Ok(start_index);
132 }
133
134 let node = &nodes[start_index];
135
136 match node {
138 Node::Object { len, count } => {
139 let skip_count = if *count > 0 { *count } else { *len * 2 + 1 };
143 Ok(start_index + skip_count)
144 }
145 Node::Array { len, count } => {
146 let skip_count = if *count > 0 { *count } else { *len + 1 };
149 Ok(start_index + skip_count)
150 }
151 Node::String(_) | Node::Static(_) => {
152 Ok(start_index + 1)
154 }
155 }
156 }
157
158 #[inline]
160 #[must_use]
161 pub fn simd_schema_match(
162 &self,
163 path: &str,
164 schema: &std::collections::HashSet<String>,
165 ) -> bool {
166 let path_bytes = path.as_bytes();
167
168 for schema_path in schema {
169 let schema_bytes = schema_path.as_bytes();
170
171 if self.simd_string_equals(path_bytes, schema_bytes) {
173 return true;
174 }
175
176 if path_bytes.len() > schema_bytes.len()
178 && path_bytes[schema_bytes.len()] == b'.'
179 && self.simd_string_equals(&path_bytes[..schema_bytes.len()], schema_bytes)
180 {
181 return true;
182 }
183
184 if schema_bytes.len() > path_bytes.len()
186 && schema_bytes[path_bytes.len()] == b'.'
187 && self.simd_string_equals(&schema_bytes[..path_bytes.len()], path_bytes)
188 {
189 return true;
190 }
191 }
192
193 false
194 }
195
196 #[must_use]
198 pub fn extract_value_simd(&self, index: usize) -> Option<SimdValue> {
199 let nodes = self.nodes();
200 if index >= nodes.len() {
201 return None;
202 }
203
204 match &nodes[index] {
205 Node::String(s) => Some(SimdValue::String(s.to_string())),
206 Node::Static(static_node) => match static_node {
207 simd_json::StaticNode::Null => Some(SimdValue::Null),
208 simd_json::StaticNode::Bool(b) => Some(SimdValue::Bool(*b)),
209 simd_json::StaticNode::I64(n) => Some(SimdValue::Number(n.to_string())),
210 simd_json::StaticNode::U64(n) => Some(SimdValue::Number(n.to_string())),
211 simd_json::StaticNode::F64(n) => Some(SimdValue::Number(n.to_string())),
212 },
213 _ => None,
214 }
215 }
216
217 #[must_use]
219 pub fn serialize_simd(
220 &self,
221 modifications: &std::collections::HashMap<String, fionn_core::OperationValue>,
222 ) -> Option<String> {
223 if modifications.is_empty() {
227 return Some(String::from_utf8_lossy(&self.data).to_string());
229 }
230
231 None }
235
236 pub fn read_field(&self, index: usize) -> Result<Node<'static>> {
241 self.nodes()
242 .get(index)
243 .copied()
244 .ok_or_else(|| DsonError::InvalidField(format!("Index {index} out of bounds")))
245 }
246
247 #[must_use]
251 #[inline]
252 pub fn should_survive(
253 &self,
254 field_path: &str,
255 schema: &std::collections::HashSet<String>,
256 ) -> bool {
257 if schema.is_empty() {
259 return true;
260 }
261
262 if schema.contains(field_path) {
264 return true;
265 }
266
267 for schema_path in schema {
269 if field_path.starts_with(schema_path)
271 && (field_path.len() == schema_path.len()
272 || field_path.as_bytes().get(schema_path.len()) == Some(&b'.'))
273 {
274 return true;
275 }
276
277 if schema_path.starts_with(field_path)
279 && (schema_path.len() == field_path.len()
280 || schema_path.as_bytes().get(field_path.len()) == Some(&b'.'))
281 {
282 return true;
283 }
284
285 if schema_path.ends_with(".*") {
287 let prefix = &schema_path[..schema_path.len() - 2];
288 if field_path.starts_with(prefix) {
289 return true;
290 }
291 }
292 }
293
294 false
295 }
296
297 pub fn filter_by_schema(&self, schema: &std::collections::HashSet<String>) -> Result<Self> {
306 let full_json = self.to_json_string()?;
309 let full_value: serde_json::Value = serde_json::from_str(&full_json)
310 .map_err(|e| fionn_core::DsonError::ParseError(format!("JSON parse error: {e}")))?;
311
312 let filtered_value = self.filter_json_by_schema(&full_value, schema, &mut Vec::new());
313 let filtered_json = serde_json::to_string(&filtered_value).map_err(|e| {
314 fionn_core::DsonError::SerializationError(format!("JSON serialize error: {e}"))
315 })?;
316
317 Self::parse(&filtered_json)
318 }
319
320 fn filter_json_by_schema(
322 &self,
323 value: &serde_json::Value,
324 schema: &std::collections::HashSet<String>,
325 current_path: &mut Vec<String>,
326 ) -> serde_json::Value {
327 match value {
328 serde_json::Value::Object(obj) => {
329 let mut filtered_obj = serde_json::Map::new();
330
331 for (key, val) in obj {
332 current_path.push(key.clone());
333 let path_str = current_path.join(".");
334
335 if self.simd_schema_match(&path_str, schema) {
337 let filtered_val = self.filter_json_by_schema(val, schema, current_path);
338 filtered_obj.insert(key.clone(), filtered_val);
339 }
340
341 current_path.pop();
342 }
343
344 serde_json::Value::Object(filtered_obj)
345 }
346 serde_json::Value::Array(arr) => {
347 let mut filtered_arr = Vec::new();
348
349 for (index, val) in arr.iter().enumerate() {
350 let array_path = if current_path.is_empty() {
352 format!("[{index}]")
353 } else {
354 format!("{}[{}]", current_path.join("."), index)
355 };
356
357 let should_include = schema.iter().any(|schema_path| {
359 schema_path == &array_path ||
360 array_path.starts_with(&format!("{schema_path}.")) ||
361 schema_path.starts_with(&format!("{array_path}.")) ||
362 schema_path.starts_with(&format!("{}[{}].", current_path.join("."), index))
364 });
365
366 if should_include {
367 current_path.push(format!("[{index}]"));
369 let filtered_val = self.filter_json_by_schema(val, schema, current_path);
370 filtered_arr.push(filtered_val);
371 current_path.pop();
372 }
373 }
374
375 serde_json::Value::Array(filtered_arr)
376 }
377 _ => value.clone(),
379 }
380 }
381
382 pub fn resolve_path(&self, path: &str) -> Result<Option<usize>> {
387 let mut components = Vec::new();
388 fionn_core::parse_simd_ref_into(path, &mut components);
389 self.resolve_path_components_ref(&components, 0, 0)
390 }
391
392 pub fn resolve_path_components_owned(
397 &self,
398 components: &[PathComponent],
399 ) -> Result<Option<usize>> {
400 self.resolve_path_components_owned_internal(components, 0, 0)
401 }
402
403 pub fn resolve_parsed_path_with_buffer<'a>(
408 &self,
409 parsed: &'a ParsedPath,
410 buffer: &mut Vec<PathComponentRef<'a>>,
411 ) -> Result<Option<usize>> {
412 parsed.components_ref(buffer);
413 self.resolve_path_components_ref(buffer, 0, 0)
414 }
415
416 pub fn resolve_parsed_path(&self, parsed: &ParsedPath) -> Result<Option<usize>> {
421 let mut buffer = Vec::new();
422 self.resolve_parsed_path_with_buffer(parsed, &mut buffer)
423 }
424
425 fn resolve_path_components_ref(
427 &self,
428 components: &[PathComponentRef<'_>],
429 start_index: usize,
430 component_index: usize,
431 ) -> Result<Option<usize>> {
432 if component_index >= components.len() {
433 return Ok(Some(start_index));
434 }
435
436 let nodes = self.nodes();
437 if start_index >= nodes.len() {
438 return Ok(None);
439 }
440
441 let component = &components[component_index];
442
443 match component {
444 PathComponentRef::Field(field_name) => {
445 self.find_field_in_object(field_name, start_index)
447 .map_or(Ok(None), |field_index| {
448 self.resolve_path_components_ref(
450 components,
451 field_index + 1,
452 component_index + 1,
453 )
454 })
455 }
456 PathComponentRef::ArrayIndex(index) => {
457 self.find_array_element(*index, start_index)
459 .map_or(Ok(None), |element_index| {
460 self.resolve_path_components_ref(
461 components,
462 element_index,
463 component_index + 1,
464 )
465 })
466 }
467 }
468 }
469
470 fn resolve_path_components_owned_internal(
472 &self,
473 components: &[PathComponent],
474 start_index: usize,
475 component_index: usize,
476 ) -> Result<Option<usize>> {
477 if component_index >= components.len() {
478 return Ok(Some(start_index));
479 }
480
481 let nodes = self.nodes();
482 if start_index >= nodes.len() {
483 return Ok(None);
484 }
485
486 let component = &components[component_index];
487
488 match component {
489 PathComponent::Field(field_name) => self
490 .find_field_in_object(field_name, start_index)
491 .map_or(Ok(None), |field_index| {
492 self.resolve_path_components_owned_internal(
493 components,
494 field_index + 1,
495 component_index + 1,
496 )
497 }),
498 PathComponent::ArrayIndex(index) => self
499 .find_array_element(*index, start_index)
500 .map_or(Ok(None), |element_index| {
501 self.resolve_path_components_owned_internal(
502 components,
503 element_index,
504 component_index + 1,
505 )
506 }),
507 }
508 }
509
510 fn find_field_in_object(&self, field_name: &str, start_index: usize) -> Option<usize> {
512 let nodes = self.nodes();
513 let mut index = start_index;
514
515 while index < nodes.len() {
518 if let Node::String(field_str) = &nodes[index] {
519 if self.simd_string_equals(field_str.as_bytes(), field_name.as_bytes()) {
521 return Some(index);
522 }
523 }
524 index += 1;
525
526 if index > start_index + 1000 {
528 break;
529 }
530 }
531
532 None
533 }
534
535 #[inline]
537 #[must_use]
538 pub fn simd_string_equals(&self, a: &[u8], b: &[u8]) -> bool {
539 a == b
541 }
542
543 fn find_array_element(&self, target_index: usize, start_index: usize) -> Option<usize> {
545 let nodes = self.nodes();
546 let mut index = start_index;
547 let mut current_element = 0;
548
549 while index < nodes.len() && current_element <= target_index {
550 match self.skip_value(index) {
552 Ok(new_index) => index = new_index,
553 Err(_) => return None,
554 }
555 current_element += 1;
556 }
557
558 if current_element > target_index {
559 Some(index - 1) } else {
561 None
562 }
563 }
564
565 pub fn to_json_string(&self) -> Result<String> {
570 self.serialize_with_modifications(&FastHashMap::default(), &FastHashSet::default())
571 }
572
573 pub fn serialize_with_modifications(
578 &self,
579 modifications: &FastHashMap<String, fionn_core::OperationValue>,
580 deletions: &FastHashSet<String>,
581 ) -> Result<String> {
582 if modifications.is_empty() && deletions.is_empty() {
584 return self.serialize_tape_to_json();
585 }
586
587 self.serialize_tape_with_overlay(modifications, deletions)
589 }
590
591 fn serialize_tape_to_json(&self) -> Result<String> {
597 self.serialize_tape_with_overlay(&FastHashMap::default(), &FastHashSet::default())
599 }
600
601 fn serialize_tape_with_overlay(
603 &self,
604 modifications: &FastHashMap<String, fionn_core::OperationValue>,
605 deletions: &FastHashSet<String>,
606 ) -> Result<String> {
607 let mut serializer = TapeSerializer::new(self, modifications, deletions);
608 serializer.serialize()
609 }
610}
611
612struct TapeSerializer<'a> {
614 tape: &'a DsonTape,
615 modifications: &'a FastHashMap<String, fionn_core::OperationValue>,
616 deletions: &'a FastHashSet<String>,
617 output: String,
618 current_path: Vec<String>,
619}
620
621impl<'a> TapeSerializer<'a> {
622 fn new(
623 tape: &'a DsonTape,
624 modifications: &'a FastHashMap<String, fionn_core::OperationValue>,
625 deletions: &'a FastHashSet<String>,
626 ) -> Self {
627 Self {
628 tape,
629 modifications,
630 deletions,
631 output: String::with_capacity(tape.data.len() * 2),
632 current_path: Vec::new(),
633 }
634 }
635
636 fn serialize(&mut self) -> Result<String> {
637 let nodes = self.tape.nodes();
638 if !nodes.is_empty() {
639 self.serialize_node(0)?;
640 }
641 Ok(self.output.clone())
642 }
643
644 fn serialize_node(&mut self, index: usize) -> Result<usize> {
645 let mut path = String::with_capacity(64);
647 for (i, component) in self.current_path.iter().enumerate() {
648 if i > 0 && !component.starts_with('[') {
649 path.push('.');
650 }
651 path.push_str(component);
652 }
653
654 if self.deletions.contains(&path) {
656 return self.tape.skip_value(index);
657 }
658
659 if let Some(value) = self.modifications.get(&path) {
661 self.serialize_operation_value(value);
662 return self.tape.skip_value(index);
663 }
664
665 let nodes = self.tape.nodes();
666 let node = &nodes[index];
667
668 match node {
669 Node::String(s) => {
670 self.output.push('"');
671 escape_json_string(s, &mut self.output);
672 self.output.push('"');
673 Ok(index + 1)
674 }
675 Node::Static(s) => {
676 match s {
677 simd_json::StaticNode::Null => self.output.push_str("null"),
678 simd_json::StaticNode::Bool(b) => {
679 self.output.push_str(if *b { "true" } else { "false" });
680 }
681 simd_json::StaticNode::I64(n) => self.output.push_str(&n.to_string()),
682 simd_json::StaticNode::U64(n) => self.output.push_str(&n.to_string()),
683 simd_json::StaticNode::F64(n) => self.output.push_str(&n.to_string()),
684 }
685 Ok(index + 1)
686 }
687 Node::Object { len, .. } => {
688 self.output.push('{');
689 let mut current_idx = index + 1;
690 let mut first = true;
691 let mut seen_keys = FastHashSet::default();
692
693 for _ in 0..*len {
694 if let Node::String(key) = &nodes[current_idx] {
696 let key_str = key.to_string();
697 seen_keys.insert(key_str.clone());
699
700 self.current_path.push(key_str.clone());
701 let mut item_path = path.clone();
709 if !item_path.is_empty() {
710 item_path.push('.');
711 }
712 item_path.push_str(&key_str);
713
714 if self.deletions.contains(&item_path) {
716 current_idx += 1;
718 current_idx = self.tape.skip_value(current_idx)?;
719 } else {
720 if !first {
721 self.output.push(',');
722 }
723 self.output.push('"');
724 escape_json_string(key, &mut self.output);
725 self.output.push('"');
726 self.output.push(':');
727
728 current_idx += 1;
730 current_idx = self.serialize_node(current_idx)?;
731 first = false;
732 }
733 self.current_path.pop();
734 }
735 }
736
737 self.serialize_added_fields(&path, first, &seen_keys);
738
739 self.output.push('}');
740 Ok(current_idx)
741 }
742 Node::Array { len, .. } => {
743 self.output.push('[');
744 let mut current_idx = index + 1;
745 let mut first = true;
746
747 for i in 0..*len {
748 let idx_str = format!("[{i}]");
749 self.current_path.push(idx_str);
750
751 if !first {
752 self.output.push(',');
753 }
754 current_idx = self.serialize_node(current_idx)?;
755 first = false;
756
757 self.current_path.pop();
758 }
759
760 self.serialize_added_array_elements(&path, *len);
762
763 self.output.push(']');
764 Ok(current_idx)
765 }
766 }
767 }
768
769 fn serialize_operation_value(&mut self, value: &fionn_core::OperationValue) {
770 match value {
772 fionn_core::OperationValue::StringRef(s) => {
773 self.output.push('"');
774 escape_json_string(s, &mut self.output);
775 self.output.push('"');
776 }
777 fionn_core::OperationValue::NumberRef(n) => self.output.push_str(n),
778 fionn_core::OperationValue::BoolRef(b) => {
779 self.output.push_str(if *b { "true" } else { "false" });
780 }
781 fionn_core::OperationValue::Null => self.output.push_str("null"),
782 fionn_core::OperationValue::ObjectRef { .. } => {
783 self.output.push_str("{}");
787 }
788 fionn_core::OperationValue::ArrayRef { .. } => {
789 self.output.push_str("[]");
791 }
792 }
793 }
794
795 fn serialize_added_fields(
796 &mut self,
797 parent_path: &str,
798 mut first: bool,
799 seen_keys: &FastHashSet<String>,
800 ) {
801 let mut implied_keys: FastHashSet<String> = FastHashSet::default();
803
804 for (path, _) in self.modifications {
805 let relative = if parent_path.is_empty() {
806 path.as_str()
807 } else {
808 if path.len() > parent_path.len()
810 && path.starts_with(parent_path)
811 && path.as_bytes()[parent_path.len()] == b'.'
812 {
813 &path[parent_path.len() + 1..]
814 } else {
815 continue;
816 }
817 };
818
819 let end = relative.find(['.', '[']).unwrap_or(relative.len());
823 if end > 0 {
824 let key = &relative[..end];
825 if !seen_keys.contains(key) {
826 implied_keys.insert(key.to_string());
827 }
828 }
829 }
830
831 let mut sorted_keys: Vec<_> = implied_keys.into_iter().collect();
836 sorted_keys.sort();
837
838 for key in sorted_keys {
839 if !first {
840 self.output.push(',');
841 }
842 self.output.push('"');
843 escape_json_string(&key, &mut self.output);
844 self.output.push('"');
845 self.output.push(':');
846
847 let full_path = if parent_path.is_empty() {
848 key.clone()
849 } else {
850 format!("{parent_path}.{key}")
851 };
852
853 if let Some(val) = self.modifications.get(&full_path) {
854 self.serialize_operation_value(val);
856 } else {
857 let mut is_array = false;
860 let prefix_bracket = format!("{full_path}[");
862 for p in self.modifications.keys() {
863 if p.starts_with(&prefix_bracket) {
864 is_array = true;
865 break;
866 }
867 }
868
869 if is_array {
870 self.output.push('[');
871 self.serialize_added_array_elements(&full_path, 0);
872 self.output.push(']');
873 } else {
874 self.output.push('{');
875 let empty_seen = FastHashSet::default();
876 self.serialize_added_fields(&full_path, true, &empty_seen);
877 self.output.push('}');
878 }
879 }
880 first = false;
881 }
882 }
883
884 fn serialize_added_array_elements(&mut self, parent_path: &str, start_index: usize) {
885 let mut max_index: Option<usize> = None;
887 let prefix = format!("{parent_path}[");
888
889 for path in self.modifications.keys() {
890 if path.starts_with(&prefix) {
891 if let Some(end_bracket) = path[prefix.len()..].find(']') {
894 let index_str = &path[prefix.len()..prefix.len() + end_bracket];
895 if let Ok(idx) = index_str.parse::<usize>() {
896 max_index = Some(max_index.map_or(idx, |m| m.max(idx)));
897 }
898 }
899 }
900 }
901
902 if let Some(max) = max_index
903 && max >= start_index
904 {
905 for i in start_index..=max {
917 if i > 0 {
923 self.output.push(',');
924 }
925
926 let idx_path = format!("{parent_path}[{i}]");
927
928 if let Some(val) = self.modifications.get(&idx_path) {
929 self.serialize_operation_value(val);
930 } else {
931 let mut is_intermediate = false;
934 let dot_prefix = format!("{idx_path}.");
935 let bracket_prefix = format!("{idx_path}[");
936
937 for p in self.modifications.keys() {
938 if p.starts_with(&dot_prefix) || p.starts_with(&bracket_prefix) {
939 is_intermediate = true;
940 break;
941 }
942 }
943
944 if is_intermediate {
945 let mut is_array_child = false;
946 for p in self.modifications.keys() {
947 if p.starts_with(&bracket_prefix) {
948 is_array_child = true;
949 break;
950 }
951 }
952
953 if is_array_child {
954 self.output.push('[');
955 self.serialize_added_array_elements(&idx_path, 0);
956 self.output.push(']');
957 } else {
958 self.output.push('{');
959 let empty_seen = FastHashSet::default();
960 self.serialize_added_fields(&idx_path, true, &empty_seen);
961 self.output.push('}');
962 }
963 } else {
964 self.output.push_str("null");
966 }
967 }
968 }
969 }
970 }
971}
972
973impl DsonTape {
974 #[inline]
976 #[must_use]
977 pub fn parse_path(path: &str) -> Vec<PathComponent> {
978 fionn_core::parse_simd(path)
979 }
980
981 pub fn reconstruct_value_from_tape(
986 &self,
987 start: usize,
988 _end: usize,
989 ) -> Result<serde_json::Value> {
990 let nodes = self.nodes();
991 if start >= nodes.len() {
992 return Ok(serde_json::Value::Null);
993 }
994
995 self.node_to_json_value(start)
996 }
997
998 fn node_to_json_value(&self, index: usize) -> Result<serde_json::Value> {
1000 let nodes = self.nodes();
1001 if index >= nodes.len() {
1002 return Ok(serde_json::Value::Null);
1003 }
1004
1005 let node = &nodes[index];
1006
1007 match node {
1008 Node::String(s) => Ok(serde_json::Value::String(s.to_string())),
1009 Node::Static(static_val) => match static_val {
1010 simd_json::StaticNode::Null => Ok(serde_json::Value::Null),
1011 simd_json::StaticNode::Bool(b) => Ok(serde_json::Value::Bool(*b)),
1012 simd_json::StaticNode::I64(n) => Ok(serde_json::Value::Number((*n).into())),
1013 simd_json::StaticNode::U64(n) => Ok(serde_json::Value::Number((*n).into())),
1014 simd_json::StaticNode::F64(n) => Ok(serde_json::Number::from_f64(*n).map_or_else(
1015 || serde_json::Value::String(n.to_string()),
1016 serde_json::Value::Number,
1017 )),
1018 },
1019 Node::Object { len, count: _ } => {
1020 let mut obj = serde_json::Map::new();
1021 let mut current_idx = index + 1;
1022
1023 for _ in 0..*len {
1024 if current_idx >= nodes.len() {
1025 break;
1026 }
1027
1028 if let Node::String(field_name) = &nodes[current_idx] {
1030 let key = field_name.to_string();
1031 current_idx += 1;
1032
1033 if current_idx < nodes.len() {
1035 let value = self.node_to_json_value(current_idx)?;
1036 current_idx = self.skip_value(current_idx)?;
1037 obj.insert(key, value);
1038 }
1039 } else {
1040 current_idx += 1;
1041 }
1042 }
1043
1044 Ok(serde_json::Value::Object(obj))
1045 }
1046 Node::Array { len, count: _ } => {
1047 let mut arr = Vec::with_capacity(*len);
1048 let mut current_idx = index + 1;
1049
1050 for _ in 0..*len {
1051 if current_idx >= nodes.len() {
1052 break;
1053 }
1054
1055 let value = self.node_to_json_value(current_idx)?;
1056 current_idx = self.skip_value(current_idx)?;
1057 arr.push(value);
1058 }
1059
1060 Ok(serde_json::Value::Array(arr))
1061 }
1062 }
1063 }
1064}
1065
1066#[cfg(test)]
1067mod tests {
1068 use super::*;
1069
1070 #[test]
1071 fn test_dson_tape_parse_simple() {
1072 let tape = DsonTape::parse(r#"{"name":"test"}"#);
1073 assert!(tape.is_ok());
1074 }
1075
1076 #[test]
1077 fn test_dson_tape_parse_array() {
1078 let tape = DsonTape::parse(r"[1, 2, 3]");
1079 assert!(tape.is_ok());
1080 }
1081
1082 #[test]
1083 fn test_dson_tape_parse_nested() {
1084 let tape = DsonTape::parse(r#"{"user":{"name":"test","age":30}}"#);
1085 assert!(tape.is_ok());
1086 }
1087
1088 #[test]
1089 fn test_dson_tape_parse_invalid() {
1090 let tape = DsonTape::parse("not valid json");
1091 assert!(tape.is_err());
1092 }
1093
1094 #[test]
1095 fn test_dson_tape_nodes() {
1096 let tape = DsonTape::parse(r#"{"name":"test"}"#).unwrap();
1097 assert!(!tape.nodes().is_empty());
1098 }
1099
1100 #[test]
1101 fn test_dson_tape_root() {
1102 let tape = DsonTape::parse(r#"{"name":"test"}"#).unwrap();
1103 let _root = tape.root();
1104 }
1106
1107 #[test]
1108 fn test_dson_tape_tape() {
1109 let tape = DsonTape::parse(r#"{"name":"test"}"#).unwrap();
1110 let _inner = tape.tape();
1111 }
1113
1114 #[test]
1115 fn test_dson_tape_skip_field() {
1116 let tape = DsonTape::parse(r#"{"name":"test","age":30}"#).unwrap();
1117 let result = tape.skip_field(0);
1118 assert!(result.is_ok());
1119 }
1120
1121 #[test]
1122 fn test_dson_tape_skip_value() {
1123 let tape = DsonTape::parse(r#"{"name":"test"}"#).unwrap();
1124 let result = tape.skip_value(0);
1125 assert!(result.is_ok());
1126 }
1127
1128 #[test]
1129 fn test_dson_tape_resolve_path_field() {
1130 let tape = DsonTape::parse(r#"{"name":"test"}"#).unwrap();
1131 let result = tape.resolve_path("name");
1132 assert!(result.is_ok());
1133 }
1134
1135 #[test]
1136 fn test_dson_tape_resolve_path_nested() {
1137 let tape = DsonTape::parse(r#"{"user":{"name":"test"}}"#).unwrap();
1138 let result = tape.resolve_path("user.name");
1139 assert!(result.is_ok());
1140 }
1141
1142 #[test]
1143 fn test_dson_tape_resolve_path_array() {
1144 let tape = DsonTape::parse(r#"{"items":[1,2,3]}"#).unwrap();
1145 let result = tape.resolve_path("items[0]");
1146 assert!(result.is_ok());
1147 }
1148
1149 #[test]
1150 fn test_dson_tape_resolve_path_not_found() {
1151 let tape = DsonTape::parse(r#"{"name":"test"}"#).unwrap();
1152 let result = tape.resolve_path("nonexistent");
1153 assert!(result.is_ok());
1154 assert!(result.unwrap().is_none());
1155 }
1156
1157 #[test]
1158 fn test_path_component_debug() {
1159 let field = PathComponent::Field("test".to_string());
1160 let debug = format!("{field:?}");
1161 assert!(debug.contains("Field"));
1162 }
1163
1164 #[test]
1165 fn test_path_component_clone() {
1166 let field = PathComponent::Field("test".to_string());
1167 let cloned = field;
1168 assert!(matches!(cloned, PathComponent::Field(_)));
1169 }
1170
1171 #[test]
1172 fn test_simd_value_debug() {
1173 let val = SimdValue::String("test".to_string());
1174 let debug = format!("{val:?}");
1175 assert!(debug.contains("String"));
1176 }
1177
1178 #[test]
1179 fn test_simd_value_clone() {
1180 let val = SimdValue::Null;
1181 let cloned = val;
1182 assert!(matches!(cloned, SimdValue::Null));
1183 }
1184
1185 #[test]
1186 fn test_parse_path_simple() {
1187 let components = DsonTape::parse_path("name");
1188 assert_eq!(components.len(), 1);
1189 assert!(matches!(&components[0], PathComponent::Field(f) if f == "name"));
1190 }
1191
1192 #[test]
1193 fn test_parse_path_nested() {
1194 let components = DsonTape::parse_path("user.name");
1195 assert_eq!(components.len(), 2);
1196 }
1197
1198 #[test]
1199 fn test_parse_path_array() {
1200 let components = DsonTape::parse_path("items[0]");
1201 assert_eq!(components.len(), 2);
1202 assert!(matches!(&components[1], PathComponent::ArrayIndex(0)));
1203 }
1204
1205 #[test]
1206 fn test_node_to_json_value_string() {
1207 let tape = DsonTape::parse(r#"{"name":"test"}"#).unwrap();
1208 let result = tape.node_to_json_value(2);
1210 assert!(result.is_ok());
1211 }
1212
1213 #[test]
1214 fn test_node_to_json_value_object() {
1215 let tape = DsonTape::parse(r#"{"name":"test"}"#).unwrap();
1216 let result = tape.node_to_json_value(0);
1217 assert!(result.is_ok());
1218 let val = result.unwrap();
1219 assert!(val.is_object());
1220 }
1221
1222 #[test]
1223 fn test_node_to_json_value_array() {
1224 let tape = DsonTape::parse(r"[1, 2, 3]").unwrap();
1225 let result = tape.node_to_json_value(0);
1226 assert!(result.is_ok());
1227 let val = result.unwrap();
1228 assert!(val.is_array());
1229 }
1230
1231 #[test]
1232 fn test_node_to_json_value_number() {
1233 let tape = DsonTape::parse(r#"{"value":42}"#).unwrap();
1234 let result = tape.node_to_json_value(2);
1235 assert!(result.is_ok());
1236 }
1237
1238 #[test]
1239 fn test_node_to_json_value_bool() {
1240 let tape = DsonTape::parse(r#"{"flag":true}"#).unwrap();
1241 let result = tape.node_to_json_value(2);
1242 assert!(result.is_ok());
1243 }
1244
1245 #[test]
1246 fn test_node_to_json_value_null() {
1247 let tape = DsonTape::parse(r#"{"value":null}"#).unwrap();
1248 let result = tape.node_to_json_value(2);
1249 assert!(result.is_ok());
1250 }
1251
1252 #[test]
1253 fn test_skip_value_out_of_bounds() {
1254 let tape = DsonTape::parse(r"{}").unwrap();
1255 let result = tape.skip_value(100);
1256 assert!(result.is_ok());
1257 }
1258
1259 #[test]
1260 fn test_simd_value_variants() {
1261 let s = SimdValue::String("test".to_string());
1262 let n = SimdValue::Number("42".to_string());
1263 let b = SimdValue::Bool(true);
1264 let null = SimdValue::Null;
1265
1266 assert!(matches!(s, SimdValue::String(_)));
1267 assert!(matches!(n, SimdValue::Number(_)));
1268 assert!(matches!(b, SimdValue::Bool(true)));
1269 assert!(matches!(null, SimdValue::Null));
1270 }
1271
1272 #[test]
1273 fn test_to_json_string() {
1274 let tape = DsonTape::parse(r#"{"name":"test"}"#).unwrap();
1275 let result = tape.to_json_string();
1276 assert!(result.is_ok());
1277 let json = result.unwrap();
1278 assert!(json.contains("name"));
1279 assert!(json.contains("test"));
1280 }
1281
1282 #[test]
1283 fn test_filter_by_schema() {
1284 let tape = DsonTape::parse(r#"{"name":"test","age":30}"#).unwrap();
1285 let schema = std::collections::HashSet::from(["name".to_string()]);
1286 let result = tape.filter_by_schema(&schema);
1287 assert!(result.is_ok());
1288 }
1289
1290 #[test]
1291 fn test_filter_by_schema_empty() {
1292 let tape = DsonTape::parse(r#"{"name":"test"}"#).unwrap();
1293 let schema = std::collections::HashSet::new();
1294 let result = tape.filter_by_schema(&schema);
1295 assert!(result.is_ok());
1296 }
1297
1298 #[test]
1299 fn test_extract_value_simd_string() {
1300 let tape = DsonTape::parse(r#"{"name":"test"}"#).unwrap();
1301 let value = tape.extract_value_simd(2);
1302 assert!(value.is_some());
1303 }
1304
1305 #[test]
1306 fn test_extract_value_simd_out_of_bounds() {
1307 let tape = DsonTape::parse(r"{}").unwrap();
1308 let value = tape.extract_value_simd(100);
1309 assert!(value.is_none());
1310 }
1311
1312 #[test]
1313 fn test_serialize_simd() {
1314 let tape = DsonTape::parse(r#"{"name":"test"}"#).unwrap();
1315 let modifications = std::collections::HashMap::new();
1316 let result = tape.serialize_simd(&modifications);
1317 let _ = result;
1319 }
1320
1321 #[test]
1322 fn test_read_field() {
1323 let tape = DsonTape::parse(r#"{"name":"test"}"#).unwrap();
1324 let result = tape.read_field(0);
1325 assert!(result.is_ok());
1326 }
1327
1328 #[test]
1329 fn test_read_field_out_of_bounds() {
1330 let tape = DsonTape::parse(r"{}").unwrap();
1331 let result = tape.read_field(100);
1332 assert!(result.is_err());
1333 }
1334
1335 #[test]
1336 fn test_should_survive_exact_match() {
1337 let tape = DsonTape::parse(r"{}").unwrap();
1338 let path = "user.name";
1339 let schema = std::collections::HashSet::from(["user.name".to_string()]);
1340 let result = tape.should_survive(path, &schema);
1341 assert!(result);
1342 }
1343
1344 #[test]
1345 fn test_should_survive_prefix_match() {
1346 let tape = DsonTape::parse(r"{}").unwrap();
1347 let path = "user.name";
1348 let schema = std::collections::HashSet::from(["user".to_string()]);
1349 let result = tape.should_survive(path, &schema);
1350 assert!(result);
1351 }
1352
1353 #[test]
1354 fn test_should_survive_no_match() {
1355 let tape = DsonTape::parse(r"{}").unwrap();
1356 let path = "other.field";
1357 let schema = std::collections::HashSet::from(["user".to_string()]);
1358 let result = tape.should_survive(path, &schema);
1359 assert!(!result);
1360 }
1361
1362 #[test]
1363 fn test_simd_schema_match() {
1364 let tape = DsonTape::parse(r#"{"name":"test"}"#).unwrap();
1365 let schema = std::collections::HashSet::from(["name".to_string()]);
1366 let result = tape.simd_schema_match("name", &schema);
1367 assert!(result);
1369 }
1370
1371 #[test]
1372 fn test_simd_schema_match_empty_schema() {
1373 let tape = DsonTape::parse(r#"{"name":"test"}"#).unwrap();
1374 let schema = std::collections::HashSet::new();
1375 let result = tape.simd_schema_match("name", &schema);
1376 assert!(!result);
1377 }
1378
1379 #[test]
1380 fn test_serialize_with_modifications() {
1381 let tape = DsonTape::parse(r#"{"name":"test"}"#).unwrap();
1382 let mut modifications = ahash::AHashMap::default();
1383 modifications.insert(
1384 "name".to_string(),
1385 fionn_core::OperationValue::StringRef("modified".to_string()),
1386 );
1387 let deletions = ahash::AHashSet::default();
1388 let result = tape.serialize_with_modifications(&modifications, &deletions);
1389 assert!(result.is_ok());
1390 }
1391
1392 #[test]
1393 fn test_serialize_with_deletions() {
1394 let tape = DsonTape::parse(r#"{"name":"test","age":30}"#).unwrap();
1395 let modifications = ahash::AHashMap::default();
1396 let mut deletions = ahash::AHashSet::default();
1397 deletions.insert("age".to_string());
1398 let result = tape.serialize_with_modifications(&modifications, &deletions);
1399 assert!(result.is_ok());
1400 }
1401
1402 #[test]
1403 fn test_simd_string_equals() {
1404 let tape = DsonTape::parse(r"{}").unwrap();
1405 assert!(tape.simd_string_equals(b"hello", b"hello"));
1406 assert!(!tape.simd_string_equals(b"hello", b"world"));
1407 }
1408
1409 #[test]
1410 fn test_simd_string_equals_different_lengths() {
1411 let tape = DsonTape::parse(r"{}").unwrap();
1412 assert!(!tape.simd_string_equals(b"hello", b"hi"));
1413 }
1414
1415 #[test]
1416 fn test_simd_string_equals_long_strings() {
1417 let tape = DsonTape::parse(r"{}").unwrap();
1418 let a = b"this is a long string for testing simd comparison";
1419 let b = b"this is a long string for testing simd comparison";
1420 assert!(tape.simd_string_equals(a, b));
1421 }
1422
1423 #[test]
1424 fn test_resolve_path_empty() {
1425 let tape = DsonTape::parse(r#"{"name":"test"}"#).unwrap();
1426 let result = tape.resolve_path("");
1427 assert!(result.is_ok());
1428 }
1429
1430 #[test]
1431 fn test_resolve_path_deep_nesting() {
1432 let tape = DsonTape::parse(r#"{"a":{"b":{"c":{"d":1}}}}"#).unwrap();
1433 let result = tape.resolve_path("a.b.c.d");
1434 assert!(result.is_ok());
1435 }
1436
1437 #[test]
1438 fn test_resolve_path_array_out_of_bounds() {
1439 let tape = DsonTape::parse(r#"{"items":[1,2,3]}"#).unwrap();
1440 let result = tape.resolve_path("items[100]");
1441 assert!(result.is_ok());
1442 assert!(result.unwrap().is_none());
1444 }
1445
1446 #[test]
1447 fn test_resolve_parsed_path() {
1448 let tape = DsonTape::parse(r#"{"user":{"name":"test"}}"#).unwrap();
1449 let parsed = fionn_core::ParsedPath::parse("user.name");
1450 let result = tape.resolve_parsed_path(&parsed);
1451 assert!(result.is_ok());
1452 }
1453
1454 #[test]
1455 fn test_node_to_json_value_nested_object() {
1456 let tape = DsonTape::parse(r#"{"user":{"name":"test","age":30}}"#).unwrap();
1457 let result = tape.node_to_json_value(0);
1458 assert!(result.is_ok());
1459 let val = result.unwrap();
1460 assert!(val.is_object());
1461 }
1462
1463 #[test]
1464 fn test_node_to_json_value_nested_array() {
1465 let tape = DsonTape::parse(r"[[1,2],[3,4]]").unwrap();
1466 let result = tape.node_to_json_value(0);
1467 assert!(result.is_ok());
1468 let val = result.unwrap();
1469 assert!(val.is_array());
1470 }
1471
1472 #[test]
1473 fn test_parse_path_empty() {
1474 let components = DsonTape::parse_path("");
1475 assert!(components.is_empty());
1476 }
1477
1478 #[test]
1479 fn test_parse_path_complex() {
1480 let components = DsonTape::parse_path("users[0].name.first");
1481 assert_eq!(components.len(), 4);
1482 }
1483
1484 #[test]
1485 fn test_reconstruct_value_from_tape() {
1486 let tape = DsonTape::parse(r#"{"name":"test"}"#).unwrap();
1487 let result = tape.reconstruct_value_from_tape(0, 10);
1488 assert!(result.is_ok());
1489 }
1490
1491 #[test]
1492 fn test_reconstruct_value_from_tape_array() {
1493 let tape = DsonTape::parse(r"[1,2,3]").unwrap();
1494 let result = tape.reconstruct_value_from_tape(0, 10);
1495 assert!(result.is_ok());
1496 }
1497
1498 #[test]
1499 fn test_path_component_array_index() {
1500 let idx = PathComponent::ArrayIndex(5);
1501 let debug = format!("{idx:?}");
1502 assert!(debug.contains("ArrayIndex"));
1503 }
1504
1505 #[test]
1506 fn test_skip_field_not_object() {
1507 let tape = DsonTape::parse(r"[1,2,3]").unwrap();
1508 let result = tape.skip_field(0);
1509 assert!(result.is_ok());
1510 }
1511
1512 #[test]
1513 fn test_skip_value_array() {
1514 let tape = DsonTape::parse(r"[1,2,3]").unwrap();
1515 let result = tape.skip_value(0);
1516 assert!(result.is_ok());
1517 assert!(result.unwrap() > 0);
1518 }
1519
1520 #[test]
1521 fn test_skip_value_string() {
1522 let tape = DsonTape::parse(r#"{"name":"test"}"#).unwrap();
1523 let result = tape.skip_value(2);
1524 assert!(result.is_ok());
1525 }
1526
1527 #[test]
1528 fn test_skip_value_static() {
1529 let tape = DsonTape::parse(r#"{"val":true}"#).unwrap();
1530 let result = tape.skip_value(2);
1531 assert!(result.is_ok());
1532 }
1533
1534 #[test]
1535 fn test_resolve_path_components_owned() {
1536 let tape = DsonTape::parse(r#"{"user":{"name":"test"}}"#).unwrap();
1537 let components = vec![
1538 PathComponent::Field("user".to_string()),
1539 PathComponent::Field("name".to_string()),
1540 ];
1541 let result = tape.resolve_path_components_owned(&components);
1542 assert!(result.is_ok());
1543 }
1544
1545 #[test]
1546 fn test_extract_value_simd_number() {
1547 let tape = DsonTape::parse(r#"{"val":42}"#).unwrap();
1548 let value = tape.extract_value_simd(2);
1549 assert!(value.is_some());
1550 assert!(matches!(value.unwrap(), SimdValue::Number(_)));
1551 }
1552
1553 #[test]
1554 fn test_extract_value_simd_bool() {
1555 let tape = DsonTape::parse(r#"{"val":true}"#).unwrap();
1556 let value = tape.extract_value_simd(2);
1557 assert!(value.is_some());
1558 assert!(matches!(value.unwrap(), SimdValue::Bool(true)));
1559 }
1560
1561 #[test]
1562 fn test_extract_value_simd_null() {
1563 let tape = DsonTape::parse(r#"{"val":null}"#).unwrap();
1564 let value = tape.extract_value_simd(2);
1565 assert!(value.is_some());
1566 assert!(matches!(value.unwrap(), SimdValue::Null));
1567 }
1568
1569 #[test]
1570 fn test_filter_by_schema_with_array() {
1571 let tape = DsonTape::parse(r#"{"items":[1,2,3],"name":"test"}"#).unwrap();
1572 let schema = std::collections::HashSet::from(["items".to_string()]);
1573 let result = tape.filter_by_schema(&schema);
1574 assert!(result.is_ok());
1575 }
1576
1577 #[test]
1578 fn test_filter_by_schema_nested_array() {
1579 let tape = DsonTape::parse(r#"{"data":{"items":[{"id":1},{"id":2}]}}"#).unwrap();
1580 let schema =
1581 std::collections::HashSet::from(["data".to_string(), "data.items".to_string()]);
1582 let result = tape.filter_by_schema(&schema);
1583 assert!(result.is_ok());
1584 }
1585
1586 #[test]
1587 fn test_resolve_path_with_array_index() {
1588 let tape = DsonTape::parse(r#"{"items":["a","b","c"]}"#).unwrap();
1589 let components = vec![
1590 PathComponent::Field("items".to_string()),
1591 PathComponent::ArrayIndex(1),
1592 ];
1593 let result = tape.resolve_path_components_owned(&components);
1594 assert!(result.is_ok());
1595 }
1596
1597 #[test]
1598 fn test_resolve_path_nested_array() {
1599 let tape = DsonTape::parse(r#"{"data":[{"name":"first"},{"name":"second"}]}"#).unwrap();
1600 let components = vec![
1601 PathComponent::Field("data".to_string()),
1602 PathComponent::ArrayIndex(0),
1603 PathComponent::Field("name".to_string()),
1604 ];
1605 let result = tape.resolve_path_components_owned(&components);
1606 assert!(result.is_ok());
1607 }
1608
1609 #[test]
1610 fn test_resolve_path_missing_field() {
1611 let tape = DsonTape::parse(r#"{"name":"test"}"#).unwrap();
1612 let components = vec![PathComponent::Field("nonexistent".to_string())];
1613 let result = tape.resolve_path_components_owned(&components);
1614 assert!(result.is_ok());
1615 assert!(result.unwrap().is_none());
1616 }
1617
1618 #[test]
1619 fn test_resolve_path_missing_array_index() {
1620 let tape = DsonTape::parse(r#"{"items":["a","b"]}"#).unwrap();
1621 let components = vec![
1622 PathComponent::Field("items".to_string()),
1623 PathComponent::ArrayIndex(99),
1624 ];
1625 let result = tape.resolve_path_components_owned(&components);
1626 assert!(result.is_ok());
1627 }
1629
1630 #[test]
1631 fn test_serialize_with_modifications_nested() {
1632 let tape = DsonTape::parse(r#"{"user":{"name":"Alice"}}"#).unwrap();
1633 let mut modifications = FastHashMap::default();
1634 modifications.insert(
1635 "user.email".to_string(),
1636 fionn_core::OperationValue::StringRef("alice@example.com".to_string()),
1637 );
1638 let deletions = FastHashSet::default();
1639 let result = tape.serialize_with_modifications(&modifications, &deletions);
1640 assert!(result.is_ok());
1641 }
1642
1643 #[test]
1644 fn test_serialize_with_deletions_extended() {
1645 let tape = DsonTape::parse(r#"{"name":"Alice","age":30}"#).unwrap();
1646 let modifications = FastHashMap::default();
1647 let mut deletions = FastHashSet::default();
1648 deletions.insert("age".to_string());
1649 let result = tape.serialize_with_modifications(&modifications, &deletions);
1650 assert!(result.is_ok());
1651 let output = result.unwrap();
1652 assert!(!output.contains("\"age\""));
1653 }
1654
1655 #[test]
1656 fn test_serialize_with_array_modifications() {
1657 let tape = DsonTape::parse(r#"{"items":["a","b","c"]}"#).unwrap();
1658 let mut modifications = FastHashMap::default();
1659 modifications.insert(
1660 "items[1]".to_string(),
1661 fionn_core::OperationValue::StringRef("modified".to_string()),
1662 );
1663 let deletions = FastHashSet::default();
1664 let result = tape.serialize_with_modifications(&modifications, &deletions);
1665 assert!(result.is_ok());
1666 }
1667
1668 #[test]
1669 fn test_reconstruct_value_from_tape_extended() {
1670 let tape = DsonTape::parse(r#"{"name":"test","age":42}"#).unwrap();
1671 let node_count = tape.nodes().len();
1672 let result = tape.reconstruct_value_from_tape(0, node_count);
1673 assert!(result.is_ok());
1674 let value = result.unwrap();
1675 assert!(value.is_object());
1676 }
1677
1678 #[test]
1679 fn test_reconstruct_value_from_tape_array_extended() {
1680 let tape = DsonTape::parse(r"[1,2,3]").unwrap();
1681 let node_count = tape.nodes().len();
1682 let result = tape.reconstruct_value_from_tape(0, node_count);
1683 assert!(result.is_ok());
1684 let value = result.unwrap();
1685 assert!(value.is_array());
1686 }
1687
1688 #[test]
1689 fn test_field_matches_schema_prefix() {
1690 let tape = DsonTape::parse(r#"{"user":{"name":"test"}}"#).unwrap();
1691 let schema = std::collections::HashSet::from(["user".to_string()]);
1692 let result = tape.filter_by_schema(&schema);
1694 assert!(result.is_ok());
1695 }
1696
1697 #[test]
1698 fn test_field_matches_schema_wildcard() {
1699 let tape = DsonTape::parse(r#"{"users":{"alice":{"id":1},"bob":{"id":2}}}"#).unwrap();
1700 let schema = std::collections::HashSet::from(["users.**".to_string()]);
1701 let result = tape.filter_by_schema(&schema);
1702 assert!(result.is_ok());
1703 }
1704
1705 #[test]
1706 fn test_empty_tape_serialization() {
1707 let tape = DsonTape::parse(r"{}").unwrap();
1708 let modifications = FastHashMap::default();
1709 let deletions = FastHashSet::default();
1710 let result = tape.serialize_with_modifications(&modifications, &deletions);
1711 assert!(result.is_ok());
1712 assert_eq!(result.unwrap(), "{}");
1713 }
1714
1715 #[test]
1716 fn test_empty_array_serialization() {
1717 let tape = DsonTape::parse(r"[]").unwrap();
1718 let modifications = FastHashMap::default();
1719 let deletions = FastHashSet::default();
1720 let result = tape.serialize_with_modifications(&modifications, &deletions);
1721 assert!(result.is_ok());
1722 assert_eq!(result.unwrap(), "[]");
1723 }
1724
1725 #[test]
1726 fn test_extract_value_simd_i64() {
1727 let tape = DsonTape::parse(r#"{"val":9223372036854775807}"#).unwrap();
1728 let value = tape.extract_value_simd(2);
1729 assert!(value.is_some());
1731 }
1732
1733 #[test]
1734 fn test_extract_value_simd_f64() {
1735 let tape = DsonTape::parse(r#"{"val":3.14159}"#).unwrap();
1736 let value = tape.extract_value_simd(2);
1737 assert!(value.is_some());
1738 if let Some(SimdValue::Number(n)) = value {
1739 assert!(n.contains("3.14"));
1740 }
1741 }
1742
1743 #[test]
1744 fn test_filter_by_schema_empty_result() {
1745 let tape = DsonTape::parse(r#"{"name":"test","age":30}"#).unwrap();
1746 let schema = std::collections::HashSet::from(["nonexistent".to_string()]);
1747 let result = tape.filter_by_schema(&schema);
1748 assert!(result.is_ok());
1749 }
1750
1751 #[test]
1752 fn test_filter_by_schema_all_fields() {
1753 let tape = DsonTape::parse(r#"{"name":"test","age":30}"#).unwrap();
1754 let schema = std::collections::HashSet::from(["name".to_string(), "age".to_string()]);
1755 let result = tape.filter_by_schema(&schema);
1756 assert!(result.is_ok());
1757 }
1758
1759 #[test]
1760 fn test_get_field_value_missing() {
1761 let _tape = DsonTape::parse(r#"{"name":"test"}"#).unwrap();
1762 let components = DsonTape::parse_path("missing");
1764 assert_eq!(components.len(), 1);
1765 }
1766
1767 #[test]
1768 fn test_get_nested_field_path() {
1769 let tape = DsonTape::parse(r#"{"user":{"name":"test"}}"#).unwrap();
1770 let components = DsonTape::parse_path("user.name");
1771 assert_eq!(components.len(), 2);
1772 let _ = tape;
1773 }
1774
1775 #[test]
1776 fn test_skip_value_nested_object() {
1777 let tape = DsonTape::parse(r#"{"outer":{"inner":{"deep":"value"}}}"#).unwrap();
1778 let result = tape.skip_value(0);
1779 assert!(result.is_ok());
1780 }
1781
1782 #[test]
1783 fn test_skip_value_nested_array() {
1784 let tape = DsonTape::parse(r"[[1,2],[3,4],[5,6]]").unwrap();
1785 let result = tape.skip_value(0);
1786 assert!(result.is_ok());
1787 }
1788
1789 #[test]
1790 fn test_serialize_with_modifications_add_new_field() {
1791 let tape = DsonTape::parse(r#"{"existing":"value"}"#).unwrap();
1792 let mut modifications = FastHashMap::default();
1793 modifications.insert(
1794 "new_field".to_string(),
1795 fionn_core::OperationValue::StringRef("new_value".to_string()),
1796 );
1797 let deletions = FastHashSet::default();
1798 let result = tape.serialize_with_modifications(&modifications, &deletions);
1799 assert!(result.is_ok());
1800 let output = result.unwrap();
1801 assert!(output.contains("new_field") || output.contains("existing"));
1802 }
1803
1804 #[test]
1805 fn test_serialize_with_modifications_number() {
1806 let tape = DsonTape::parse(r#"{"value":42}"#).unwrap();
1807 let mut modifications = FastHashMap::default();
1808 modifications.insert(
1809 "value".to_string(),
1810 fionn_core::OperationValue::NumberRef("100".to_string()),
1811 );
1812 let deletions = FastHashSet::default();
1813 let result = tape.serialize_with_modifications(&modifications, &deletions);
1814 assert!(result.is_ok());
1815 }
1816
1817 #[test]
1818 fn test_serialize_with_modifications_bool() {
1819 let tape = DsonTape::parse(r#"{"flag":true}"#).unwrap();
1820 let mut modifications = FastHashMap::default();
1821 modifications.insert(
1822 "flag".to_string(),
1823 fionn_core::OperationValue::BoolRef(false),
1824 );
1825 let deletions = FastHashSet::default();
1826 let result = tape.serialize_with_modifications(&modifications, &deletions);
1827 assert!(result.is_ok());
1828 }
1829
1830 #[test]
1831 fn test_serialize_with_modifications_null() {
1832 let tape = DsonTape::parse(r#"{"value":"test"}"#).unwrap();
1833 let mut modifications = FastHashMap::default();
1834 modifications.insert("value".to_string(), fionn_core::OperationValue::Null);
1835 let deletions = FastHashSet::default();
1836 let result = tape.serialize_with_modifications(&modifications, &deletions);
1837 assert!(result.is_ok());
1838 }
1839
1840 #[test]
1841 fn test_path_component_field() {
1842 let component = PathComponent::Field("test".to_string());
1843 match component {
1844 PathComponent::Field(name) => assert_eq!(name, "test"),
1845 PathComponent::ArrayIndex(_) => panic!("Expected Field"),
1846 }
1847 }
1848
1849 #[test]
1850 fn test_path_component_array_index_match() {
1851 let component = PathComponent::ArrayIndex(5);
1852 match component {
1853 PathComponent::ArrayIndex(idx) => assert_eq!(idx, 5),
1854 PathComponent::Field(_) => panic!("Expected ArrayIndex"),
1855 }
1856 }
1857
1858 #[test]
1859 fn test_parse_complex_path() {
1860 let components = DsonTape::parse_path("users[0].profile.name");
1861 assert_eq!(components.len(), 4);
1862 }
1863
1864 #[test]
1865 fn test_to_json_string_array() {
1866 let tape = DsonTape::parse(r#"[1,"two",true,null]"#).unwrap();
1867 let result = tape.to_json_string();
1868 assert!(result.is_ok());
1869 let output = result.unwrap();
1870 assert!(output.contains('1'));
1871 assert!(output.contains("two"));
1872 }
1873
1874 #[test]
1875 fn test_to_json_string_nested() {
1876 let tape = DsonTape::parse(r#"{"a":{"b":{"c":1}}}"#).unwrap();
1877 let result = tape.to_json_string();
1878 assert!(result.is_ok());
1879 }
1880
1881 #[test]
1882 fn test_simd_value_string() {
1883 let value = SimdValue::String("test".to_string());
1884 match value {
1885 SimdValue::String(s) => assert_eq!(s, "test"),
1886 _ => panic!("Expected String"),
1887 }
1888 }
1889
1890 #[test]
1891 fn test_simd_value_number_display() {
1892 let value = SimdValue::Number("42".to_string());
1893 let debug_str = format!("{value:?}");
1894 assert!(debug_str.contains("42"));
1895 }
1896
1897 #[test]
1898 fn test_serialize_with_deep_nesting() {
1899 let tape = DsonTape::parse(r#"{"a":{"b":{"c":{"d":{"e":1}}}}}"#).unwrap();
1900 let modifications = FastHashMap::default();
1901 let deletions = FastHashSet::default();
1902 let result = tape.serialize_with_modifications(&modifications, &deletions);
1903 assert!(result.is_ok());
1904 }
1905
1906 #[test]
1907 fn test_serialize_with_array_of_objects() {
1908 let tape = DsonTape::parse(r#"{"items":[{"id":1},{"id":2}]}"#).unwrap();
1909 let modifications = FastHashMap::default();
1910 let deletions = FastHashSet::default();
1911 let result = tape.serialize_with_modifications(&modifications, &deletions);
1912 assert!(result.is_ok());
1913 }
1914
1915 #[test]
1916 fn test_filter_by_schema_deep_path() {
1917 let tape = DsonTape::parse(r#"{"user":{"profile":{"name":"test"}}}"#).unwrap();
1918 let schema = std::collections::HashSet::from([
1919 "user".to_string(),
1920 "user.profile".to_string(),
1921 "user.profile.name".to_string(),
1922 ]);
1923 let result = tape.filter_by_schema(&schema);
1924 assert!(result.is_ok());
1925 }
1926
1927 #[test]
1928 fn test_skip_field_out_of_bounds() {
1929 let tape = DsonTape::parse(r#"{"a": 1}"#).unwrap();
1930 let result = tape.skip_field(100);
1932 assert!(result.is_ok());
1933 assert!(result.unwrap().is_none());
1934 }
1935
1936 #[test]
1937 fn test_skip_field_on_string() {
1938 let tape = DsonTape::parse(r#"{"name": "value"}"#).unwrap();
1939 let result = tape.skip_field(1);
1941 assert!(result.is_ok());
1942 }
1943
1944 #[test]
1945 fn test_serialize_with_object_ref() {
1946 let tape = DsonTape::parse(r#"{"a": 1}"#).unwrap();
1947 let mut modifications = FastHashMap::default();
1948 modifications.insert(
1949 "new".to_string(),
1950 fionn_core::OperationValue::ObjectRef { start: 0, end: 1 },
1951 );
1952 let deletions = FastHashSet::default();
1953 let result = tape.serialize_with_modifications(&modifications, &deletions);
1954 assert!(result.is_ok());
1955 }
1956
1957 #[test]
1958 fn test_serialize_with_array_ref() {
1959 let tape = DsonTape::parse(r#"{"a": 1}"#).unwrap();
1960 let mut modifications = FastHashMap::default();
1961 modifications.insert(
1962 "arr".to_string(),
1963 fionn_core::OperationValue::ArrayRef { start: 0, end: 1 },
1964 );
1965 let deletions = FastHashSet::default();
1966 let result = tape.serialize_with_modifications(&modifications, &deletions);
1967 assert!(result.is_ok());
1968 }
1969
1970 #[test]
1971 fn test_filter_by_schema_wildcard() {
1972 let tape = DsonTape::parse(r#"{"users": {"name": "test", "age": 30}}"#).unwrap();
1973 let schema = std::collections::HashSet::from(["users.*".to_string()]);
1974 let result = tape.filter_by_schema(&schema);
1975 assert!(result.is_ok());
1976 }
1977
1978 #[test]
1979 fn test_filter_by_schema_child_path() {
1980 let tape = DsonTape::parse(r#"{"user": {"profile": {"name": "test"}}}"#).unwrap();
1981 let schema =
1982 std::collections::HashSet::from(["user".to_string(), "user.profile".to_string()]);
1983 let result = tape.filter_by_schema(&schema);
1984 assert!(result.is_ok());
1985 }
1986
1987 #[test]
1988 fn test_skip_value_on_array() {
1989 let tape = DsonTape::parse(r"[[1,2],[3,4]]").unwrap();
1990 let result = tape.skip_value(0);
1991 assert!(result.is_ok());
1992 }
1993
1994 #[test]
1995 fn test_serialize_sparse_array_modifications() {
1996 let tape = DsonTape::parse(r#"{"items": []}"#).unwrap();
1997 let mut modifications = FastHashMap::default();
1998 modifications.insert(
1999 "items[2]".to_string(),
2000 fionn_core::OperationValue::StringRef("sparse".to_string()),
2001 );
2002 let deletions = FastHashSet::default();
2003 let result = tape.serialize_with_modifications(&modifications, &deletions);
2004 assert!(result.is_ok());
2005 }
2006
2007 #[test]
2008 fn test_serialize_nested_array_in_array() {
2009 let tape = DsonTape::parse(r#"{"data": []}"#).unwrap();
2010 let mut modifications = FastHashMap::default();
2011 modifications.insert(
2012 "data[0][0]".to_string(),
2013 fionn_core::OperationValue::NumberRef("42".to_string()),
2014 );
2015 let deletions = FastHashSet::default();
2016 let result = tape.serialize_with_modifications(&modifications, &deletions);
2017 assert!(result.is_ok());
2018 }
2019
2020 #[test]
2021 fn test_serialize_nested_object_in_array() {
2022 let tape = DsonTape::parse(r#"{"data": []}"#).unwrap();
2023 let mut modifications = FastHashMap::default();
2024 modifications.insert(
2025 "data[0].name".to_string(),
2026 fionn_core::OperationValue::StringRef("test".to_string()),
2027 );
2028 let deletions = FastHashSet::default();
2029 let result = tape.serialize_with_modifications(&modifications, &deletions);
2030 assert!(result.is_ok());
2031 }
2032
2033 #[test]
2034 fn test_path_survives_filter_exact_match() {
2035 let tape = DsonTape::parse(r#"{"field": "value"}"#).unwrap();
2036 let schema = std::collections::HashSet::from(["field".to_string()]);
2037 let result = tape.filter_by_schema(&schema);
2038 assert!(result.is_ok());
2039 let filtered = result.unwrap();
2040 let json = filtered.to_json_string();
2041 assert!(json.is_ok());
2042 }
2043
2044 #[test]
2045 fn test_reconstruct_value_empty_object() {
2046 let tape = DsonTape::parse(r"{}").unwrap();
2047 let result = tape.reconstruct_value_from_tape(0, 2);
2048 assert!(result.is_ok());
2049 }
2050
2051 #[test]
2052 fn test_reconstruct_value_empty_array() {
2053 let tape = DsonTape::parse(r"[]").unwrap();
2054 let result = tape.reconstruct_value_from_tape(0, 2);
2055 assert!(result.is_ok());
2056 }
2057
2058 #[test]
2059 fn test_simd_value_string_variant() {
2060 let value = SimdValue::String("test".to_string());
2061 let debug_str = format!("{value:?}");
2062 assert!(debug_str.contains("String"));
2063 }
2064
2065 #[test]
2066 fn test_simd_value_bool_variant() {
2067 let value = SimdValue::Bool(true);
2068 let debug_str = format!("{value:?}");
2069 assert!(debug_str.contains("Bool"));
2070 }
2071
2072 #[test]
2073 fn test_simd_value_null_variant() {
2074 let value = SimdValue::Null;
2075 let debug_str = format!("{value:?}");
2076 assert!(debug_str.contains("Null"));
2077 }
2078
2079 #[test]
2080 fn test_simd_value_number_variant() {
2081 let value = SimdValue::Number("3.14".to_string());
2082 let debug_str = format!("{value:?}");
2083 assert!(debug_str.contains("Number"));
2084 }
2085
2086 #[test]
2087 fn test_parse_path_with_multiple_arrays() {
2088 let components = DsonTape::parse_path("data[0].items[1].value");
2089 assert_eq!(components.len(), 5);
2090 }
2091
2092 #[test]
2093 fn test_roundtrip_escaped_quote() {
2094 let input = r#"[ "Hello, \u4e16\"emoji"]"#;
2096 let tape = DsonTape::parse(input).expect("should parse");
2097 let serialized = tape.to_json_string().expect("should serialize");
2098
2099 eprintln!("Input: {}", input);
2101 eprintln!("Serialized: {}", serialized);
2102
2103 let reparsed = DsonTape::parse(&serialized);
2105 assert!(
2106 reparsed.is_ok(),
2107 "Round-trip failed: serialized JSON is invalid: {}",
2108 serialized
2109 );
2110 }
2111
2112 #[test]
2113 fn test_roundtrip_backslash() {
2114 let input = r#"{"key": "back\\slash"}"#;
2115 let tape = DsonTape::parse(input).expect("should parse");
2116 let serialized = tape.to_json_string().expect("should serialize");
2117 let reparsed = DsonTape::parse(&serialized);
2118 assert!(
2119 reparsed.is_ok(),
2120 "Round-trip failed for backslash: {}",
2121 serialized
2122 );
2123 }
2124
2125 #[test]
2126 fn test_roundtrip_unicode_escape() {
2127 let input = r#"["Hello, \u4e16\u754c!"]"#;
2128 let tape = DsonTape::parse(input).expect("should parse");
2129 let serialized = tape.to_json_string().expect("should serialize");
2130 let reparsed = DsonTape::parse(&serialized);
2131 assert!(
2132 reparsed.is_ok(),
2133 "Round-trip failed for unicode: {}",
2134 serialized
2135 );
2136 }
2137
2138 #[test]
2141 fn test_fuzz_crash_inputs() {
2142 let crash_inputs = vec![
2143 r#"[ "Hello, \u4e16\"emoji"]"#,
2145 r#"[{"id": 1}, {"id": 2}, {"ttab\\slash\"quoid": 3}]"#,
2147 r#"[ "Hello, \u4e16\u754c!", "emoji"]"#,
2149 r#"[ "Udvrz-\\u8f02\u568b%", "asvzx"]"#,
2151 r#"[ "Hello, \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\u4e16\u754c!", "emoji"]"#,
2153 r#"[ "Hello, \r4e16\u754c!", "emoji"]"#,
2155 r#"[ "Hello, \u4e16\u054c!", "emoji"]"#,
2157 ];
2158
2159 for (i, input) in crash_inputs.iter().enumerate() {
2160 if serde_json::from_str::<serde_json::Value>(input).is_err() {
2162 continue;
2164 }
2165
2166 let tape = match DsonTape::parse(input) {
2168 Ok(t) => t,
2169 Err(_) => continue, };
2171
2172 let serialized = match tape.to_json_string() {
2174 Ok(s) => s,
2175 Err(e) => panic!("Crash input {} failed to serialize: {}", i, e),
2176 };
2177
2178 match DsonTape::parse(&serialized) {
2180 Ok(_) => {} Err(e) => panic!(
2182 "Crash input {} round-trip failed:\n Input: {}\n Serialized: {}\n Error: {}",
2183 i, input, serialized, e
2184 ),
2185 }
2186 }
2187 }
2188}