1use indexmap::IndexMap;
35use std::fmt;
36
37use crate::error::DocumentError;
38use crate::limits::{Limits, Resolved, int_exceeds};
39
40pub const MAX_DEPTH: usize = crate::limits::DEFAULT_MAX_DEPTH as usize;
43
44pub const MAX_NODES: usize = crate::limits::DEFAULT_MAX_NODES as usize;
53
54#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
56pub struct NodeId(usize);
57
58#[derive(Debug, Clone, PartialEq)]
83pub enum Scalar {
84 Null,
86 Bool(bool),
88 Int(num_bigint::BigInt),
90 Float(f64),
92 Str(String),
94 Date(String),
96 Time(String),
98 Datetime(String),
100}
101
102impl fmt::Display for Scalar {
103 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
104 match self {
105 Scalar::Null => write!(f, "null"),
106 Scalar::Bool(b) => write!(f, "{b}"),
107 Scalar::Int(i) => write!(f, "{i}"),
108 Scalar::Float(x) => write!(f, "{x}"),
109 Scalar::Str(s) => write!(f, "{s:?}"),
110 Scalar::Date(s) | Scalar::Time(s) | Scalar::Datetime(s) => write!(f, "{s}"),
111 }
112 }
113}
114
115#[derive(Debug, Clone, PartialEq)]
121pub enum Value {
122 Null,
124 Bool(bool),
126 Int(num_bigint::BigInt),
128 Float(f64),
130 Str(String),
132 Date(String),
136 Time(String),
138 Datetime(String),
140 Array(Vec<Value>),
142 Object(IndexMap<String, Value>),
144}
145
146impl Value {
147 #[cfg(test)]
153 fn as_object(&self) -> Option<&IndexMap<String, Value>> {
154 match self {
155 Value::Object(m) => Some(m),
156 _ => None,
157 }
158 }
159}
160
161impl From<Scalar> for Value {
162 fn from(s: Scalar) -> Self {
163 match s {
164 Scalar::Null => Value::Null,
165 Scalar::Bool(b) => Value::Bool(b),
166 Scalar::Int(i) => Value::Int(i),
167 Scalar::Float(x) => Value::Float(x),
168 Scalar::Str(s) => Value::Str(s),
169 Scalar::Date(s) => Value::Date(s),
170 Scalar::Time(s) => Value::Time(s),
171 Scalar::Datetime(s) => Value::Datetime(s),
172 }
173 }
174}
175
176#[derive(Debug, Clone)]
177enum NodeData {
178 Leaf(Scalar),
179 Internal(Vec<(String, NodeId)>),
180}
181
182#[derive(Debug, Clone)]
183struct Entry {
184 data: NodeData,
185 depth: usize,
194}
195
196pub(crate) fn check_write_depth(
201 depth: usize,
202 path: &str,
203 max_depth: usize,
204) -> Result<(), DocumentError> {
205 if depth > max_depth {
206 return Err(DocumentError::with_code(
207 path,
208 "document.limit.depth",
209 format!("nesting exceeds the maximum depth ({max_depth})"),
210 ));
211 }
212 Ok(())
213}
214
215#[derive(Debug, Clone)]
219struct Arena {
220 entries: Vec<Entry>,
221 containers: usize,
222 limits: Resolved,
223}
224
225impl Arena {
226 fn new(limits: Resolved) -> Arena {
227 Arena {
228 entries: Vec::new(),
229 containers: 0,
230 limits,
231 }
232 }
233}
234
235pub(crate) fn join(path: &str, key: &str) -> String {
236 let mut s = String::with_capacity(path.len() + key.len() + 4);
237 s.push_str(path);
238 crate::report::push_label_segment(&mut s, key);
239 s
240}
241
242struct ChildSpec<'a> {
247 path: String,
248 depth: usize,
249 value: &'a Value,
250}
251
252fn child_specs<'a>(
253 v: &'a Value,
254 path: &str,
255 depth: usize,
256) -> Result<Vec<ChildSpec<'a>>, DocumentError> {
257 match v {
258 Value::Array(items) => {
259 let mut out = Vec::with_capacity(items.len());
260 for (i, item) in items.iter().enumerate() {
261 let ip = if items.len() == 1 {
263 path.to_string()
264 } else {
265 format!("{path}[{i}]")
266 };
267 if matches!(item, Value::Array(_)) {
268 return Err(DocumentError::with_code(
269 ip,
270 "document.unlabeled-element",
271 "an array of arrays has no labeled-edge form",
272 ));
273 }
274 out.push(ChildSpec {
275 path: ip,
276 depth: depth + 1,
277 value: item,
278 });
279 }
280 Ok(out)
281 }
282 other => Ok(vec![ChildSpec {
283 path: path.to_string(),
284 depth,
285 value: other,
286 }]),
287 }
288}
289
290fn build_node(
293 arena: &mut Arena,
294 value: &Value,
295 path: &str,
296 depth: usize,
297) -> Result<NodeId, DocumentError> {
298 check_write_depth(depth, path, arena.limits.max_depth)?;
299 match value {
300 Value::Object(map) => {
301 let mut edges = Vec::new();
302 for (k, v) in map {
303 let kp = join(path, k);
304 for spec in child_specs(v, &kp, depth + 1)? {
305 let cid = build_node(arena, spec.value, &spec.path, spec.depth)?;
306 edges.push((k.clone(), cid));
307 }
308 }
309 push(arena, NodeData::Internal(edges), depth, path)
310 }
311 Value::Array(_) => Err(DocumentError::with_code(
312 path,
313 "document.unlabeled-element",
314 "a bare array has no labeled-edge form (arrays appear only as a repeated field)",
315 )),
316 Value::Null => push(arena, NodeData::Leaf(Scalar::Null), depth, path),
322 Value::Bool(b) => push(arena, NodeData::Leaf(Scalar::Bool(*b)), depth, path),
323 Value::Int(i) => {
324 if int_exceeds(i, arena.limits.max_int_digits) {
325 return Err(arena.limits.int_digits_error(path));
326 }
327 push(arena, NodeData::Leaf(Scalar::Int(i.clone())), depth, path)
328 }
329 Value::Float(x) => push(arena, NodeData::Leaf(Scalar::Float(*x)), depth, path),
330 Value::Date(s) => push(arena, NodeData::Leaf(Scalar::Date(s.clone())), depth, path),
331 Value::Time(s) => push(arena, NodeData::Leaf(Scalar::Time(s.clone())), depth, path),
332 Value::Datetime(s) => push(
333 arena,
334 NodeData::Leaf(Scalar::Datetime(s.clone())),
335 depth,
336 path,
337 ),
338 Value::Str(s) => push(arena, NodeData::Leaf(Scalar::Str(s.clone())), depth, path),
339 }
340}
341
342fn push(
345 arena: &mut Arena,
346 data: NodeData,
347 depth: usize,
348 path: &str,
349) -> Result<NodeId, DocumentError> {
350 if matches!(data, NodeData::Internal(_)) {
351 if arena.containers >= arena.limits.max_nodes {
352 return Err(DocumentError::with_code(
353 path,
354 "document.limit.nodes",
355 format!(
356 "document exceeds the maximum node count ({})",
357 arena.limits.max_nodes
358 ),
359 ));
360 }
361 arena.containers += 1;
362 }
363 let id = NodeId(arena.entries.len());
364 arena.entries.push(Entry { data, depth });
365 Ok(id)
366}
367
368#[derive(Debug, Clone)]
370pub struct Doc {
371 arena: Arena,
372 root: NodeId,
373}
374
375impl Doc {
376 pub fn of(value: &Value) -> Result<Doc, DocumentError> {
378 Doc::of_resolved(value, Resolved::DEFAULT)
379 }
380
381 pub fn of_with(value: &Value, limits: &Limits) -> Result<Doc, DocumentError> {
386 Doc::of_resolved(value, limits.resolve()?)
387 }
388
389 pub(crate) fn of_resolved(value: &Value, limits: Resolved) -> Result<Doc, DocumentError> {
390 let mut arena = Arena::new(limits);
391 let root = build_node(&mut arena, value, "$", 0)?;
392 Ok(Doc { arena, root })
393 }
394
395 pub fn root(&self) -> Cursor<'_> {
397 Cursor {
398 doc: self,
399 id: self.root,
400 path: "$".to_string(),
401 }
402 }
403
404 fn entry(&self, id: NodeId) -> &Entry {
405 &self.arena.entries[id.0]
406 }
407
408 pub fn add(
412 &mut self,
413 at: NodeId,
414 path: &str,
415 label: &str,
416 value: &Value,
417 ) -> Result<NodeId, DocumentError> {
418 self.require_internal(at, path, "add")?;
419 let attach_depth = self.entry(at).depth;
420 let child_path = join(path, label);
421 let cid = build_node(&mut self.arena, value, &child_path, attach_depth + 1)?;
422 let edges = self.internal_edges_mut(at, path, "add")?;
423 edges.push((label.to_string(), cid));
424 Ok(cid)
425 }
426
427 pub fn set(
430 &mut self,
431 at: NodeId,
432 path: &str,
433 label: &str,
434 value: &Value,
435 ) -> Result<NodeId, DocumentError> {
436 self.require_internal(at, path, "set")?;
437 let attach_depth = self.entry(at).depth;
438 let child_path = join(path, label);
439 let cid = build_node(&mut self.arena, value, &child_path, attach_depth + 1)?;
440 let edges = self.internal_edges_mut(at, path, "set")?;
441 let mut first: Option<usize> = None;
442 let mut kept: Vec<(String, NodeId)> = Vec::with_capacity(edges.len());
443 for (lbl, child) in edges.drain(..) {
444 if lbl == label {
445 if first.is_none() {
446 first = Some(kept.len());
447 kept.push((label.to_string(), cid));
448 }
449 } else {
451 kept.push((lbl, child));
452 }
453 }
454 if first.is_none() {
455 kept.push((label.to_string(), cid));
456 }
457 *edges = kept;
458 Ok(cid)
459 }
460
461 pub fn remove(&mut self, at: NodeId, path: &str, label: &str) -> Result<(), DocumentError> {
463 self.require_internal(at, path, "remove")?;
464 let edges = self.internal_edges_mut(at, path, "remove")?;
465 edges.retain(|(lbl, _)| lbl != label);
466 Ok(())
467 }
468
469 fn require_internal(&self, id: NodeId, path: &str, op: &str) -> Result<(), DocumentError> {
470 match self.entry(id).data {
471 NodeData::Internal(_) => Ok(()),
472 NodeData::Leaf(_) => Err(DocumentError::new(path, format!("cannot {op} on a leaf"))),
473 }
474 }
475
476 fn internal_edges_mut(
487 &mut self,
488 at: NodeId,
489 path: &str,
490 op: &str,
491 ) -> Result<&mut Vec<(String, NodeId)>, DocumentError> {
492 match &mut self.arena.entries[at.0].data {
493 NodeData::Internal(edges) => Ok(edges),
494 NodeData::Leaf(_) => Err(DocumentError::new(path, format!("cannot {op} on a leaf"))),
495 }
496 }
497
498 pub fn to_grouped(&self) -> Value {
501 self.grouped_at(self.root)
502 }
503
504 pub(crate) fn has_interleaving_loss(&self) -> bool {
515 self.node_has_interleaving_loss(self.root)
516 }
517
518 fn node_has_interleaving_loss(&self, id: NodeId) -> bool {
519 match &self.entry(id).data {
520 NodeData::Leaf(_) => false,
521 NodeData::Internal(edges) => {
522 let mut closed: std::collections::HashSet<&str> = std::collections::HashSet::new();
523 let mut prev_label: Option<&str> = None;
524 for (label, _) in edges {
525 if let Some(p) = prev_label
526 && p != label.as_str()
527 {
528 closed.insert(p);
529 }
530 if closed.contains(label.as_str()) {
531 return true;
532 }
533 prev_label = Some(label.as_str());
534 }
535 edges
536 .iter()
537 .any(|(_, child)| self.node_has_interleaving_loss(*child))
538 }
539 }
540 }
541
542 fn grouped_at(&self, id: NodeId) -> Value {
546 match &self.entry(id).data {
547 NodeData::Leaf(s) => Value::from(s.clone()),
548 NodeData::Internal(edges) => {
549 let mut counts: IndexMap<&str, usize> = IndexMap::new();
550 for (label, _) in edges {
551 *counts.entry(label.as_str()).or_insert(0) += 1;
552 }
553 let mut out: IndexMap<String, Value> = IndexMap::new();
554 for (label, child) in edges {
555 let g = self.grouped_at(*child);
556 if counts[label.as_str()] > 1 {
557 match out.get_mut(label.as_str()) {
558 Some(Value::Array(arr)) => arr.push(g),
559 _ => {
560 out.insert(label.clone(), Value::Array(vec![g]));
561 }
562 }
563 } else {
564 out.insert(label.clone(), g);
565 }
566 }
567 Value::Object(out)
568 }
569 }
570 }
571
572 pub fn to_data(&self) -> Value {
574 self.data_at(self.root)
575 }
576
577 fn data_at(&self, id: NodeId) -> Value {
578 match &self.entry(id).data {
579 NodeData::Leaf(s) => Value::from(s.clone()),
580 NodeData::Internal(edges) => {
581 let mut map = IndexMap::new();
582 for (label, child) in edges {
589 map.insert(label.clone(), self.data_at(*child));
590 }
591 Value::Object(map)
592 }
593 }
594 }
595
596 pub fn eq_doc(&self, other: &Doc) -> bool {
599 self.node_eq(self.root, other, other.root)
600 }
601
602 fn node_eq(&self, a: NodeId, other: &Doc, b: NodeId) -> bool {
603 match (&self.entry(a).data, &other.entry(b).data) {
604 (NodeData::Leaf(x), NodeData::Leaf(y)) => x == y,
605 (NodeData::Internal(xs), NodeData::Internal(ys)) => {
606 xs.len() == ys.len()
607 && xs
608 .iter()
609 .zip(ys.iter())
610 .all(|((la, ca), (lb, cb))| la == lb && self.node_eq(*ca, other, *cb))
611 }
612 _ => false,
613 }
614 }
615}
616
617#[derive(Debug, Clone)]
624pub struct Cursor<'a> {
625 doc: &'a Doc,
626 id: NodeId,
627 pub path: String,
629}
630
631impl<'a> Cursor<'a> {
632 pub fn id(&self) -> NodeId {
634 self.id
635 }
636
637 pub fn is_leaf(&self) -> bool {
639 matches!(self.doc.entry(self.id).data, NodeData::Leaf(_))
640 }
641
642 pub fn value(&self) -> Result<&'a Scalar, DocumentError> {
644 match &self.doc.entry(self.id).data {
645 NodeData::Leaf(s) => Ok(s),
646 NodeData::Internal(_) => Err(DocumentError::new(&self.path, "not a leaf; use edges()")),
647 }
648 }
649
650 pub fn edges(&self) -> Result<Vec<(String, Cursor<'a>)>, DocumentError> {
652 match &self.doc.entry(self.id).data {
653 NodeData::Internal(edges) => {
654 let mut out = Vec::with_capacity(edges.len());
655 for (label, index, child) in with_occurrence_indices(edges) {
656 let cp = crate::report::child_path(&self.path, label, index);
657 out.push((
658 label.to_string(),
659 Cursor {
660 doc: self.doc,
661 id: child,
662 path: cp,
663 },
664 ));
665 }
666 Ok(out)
667 }
668 NodeData::Leaf(_) => Err(DocumentError::new(&self.path, "a leaf has no edges")),
669 }
670 }
671
672 pub(crate) fn internal_edges(&self) -> Result<&'a [(String, NodeId)], DocumentError> {
680 match &self.doc.entry(self.id).data {
681 NodeData::Internal(edges) => Ok(edges),
682 NodeData::Leaf(_) => Err(DocumentError::new(&self.path, "a leaf has no edges")),
683 }
684 }
685
686 pub(crate) fn raw_edges(&self) -> Result<Vec<RawEdge<'a>>, DocumentError> {
689 match &self.doc.entry(self.id).data {
690 NodeData::Internal(edges) => Ok(with_occurrence_indices(edges).collect()),
691 NodeData::Leaf(_) => Err(DocumentError::new(&self.path, "a leaf has no edges")),
692 }
693 }
694
695 pub(crate) fn seek(&self, id: NodeId) -> Cursor<'a> {
700 Cursor {
701 doc: self.doc,
702 id,
703 path: String::new(),
704 }
705 }
706
707 pub fn labels(&self) -> Vec<String> {
709 let mut seen = std::collections::HashSet::new();
710 let mut out = Vec::new();
711 if let NodeData::Internal(edges) = &self.doc.entry(self.id).data {
712 for (label, _) in edges {
713 if seen.insert(label.clone()) {
714 out.push(label.clone());
715 }
716 }
717 }
718 out
719 }
720
721 pub fn get(&self, label: &str) -> Vec<Cursor<'a>> {
723 self.edges()
724 .into_iter()
725 .flatten()
726 .filter(|(lbl, _)| lbl == label)
727 .map(|(_, c)| c)
728 .collect()
729 }
730
731 pub fn get_one(&self, label: &str) -> Result<Cursor<'a>, DocumentError> {
733 let mut cs = self.get(label);
734 if cs.len() != 1 {
735 return Err(DocumentError::new(
736 &self.path,
737 format!("expected exactly one {label:?}, found {}", cs.len()),
738 ));
739 }
740 Ok(cs.remove(0))
741 }
742
743 pub fn count(&self, label: &str) -> usize {
745 if let NodeData::Internal(edges) = &self.doc.entry(self.id).data {
746 edges.iter().filter(|(lbl, _)| lbl == label).count()
747 } else {
748 0
749 }
750 }
751
752 pub fn child(&self, label: &str) -> Result<Cursor<'a>, DocumentError> {
754 self.get_one(label)
755 }
756
757 pub fn to_raw(&self) -> RawNode {
764 self.doc.raw_at(self.id)
765 }
766}
767
768#[derive(Debug, Clone, PartialEq)]
780pub enum RawNode {
781 Leaf(Scalar),
783 Edges(Vec<(String, RawNode)>),
785}
786
787impl Doc {
788 pub fn from_raw(root: RawNode) -> Result<Doc, DocumentError> {
792 Doc::from_raw_resolved(root, Resolved::DEFAULT)
793 }
794
795 pub fn from_raw_with(root: RawNode, limits: &Limits) -> Result<Doc, DocumentError> {
802 Doc::from_raw_resolved(root, limits.resolve()?)
803 }
804
805 pub(crate) fn from_raw_resolved(root: RawNode, limits: Resolved) -> Result<Doc, DocumentError> {
806 let mut arena = Arena::new(limits);
807 let root_id = push_raw(&mut arena, root, 0)?;
808 Ok(Doc {
809 arena,
810 root: root_id,
811 })
812 }
813
814 pub fn to_raw(&self) -> RawNode {
817 self.raw_at(self.root)
818 }
819
820 fn raw_at(&self, id: NodeId) -> RawNode {
821 let entry = self.entry(id);
822 match &entry.data {
823 NodeData::Leaf(s) => RawNode::Leaf(s.clone()),
824 NodeData::Internal(edges) => RawNode::Edges(
825 edges
826 .iter()
827 .map(|(label, child)| (label.clone(), self.raw_at(*child)))
828 .collect(),
829 ),
830 }
831 }
832}
833
834impl Doc {
841 pub fn from_format(name: &str, text: &str) -> Result<Doc, crate::error::OmnistError> {
845 let fmt = crate::registry::get_format(name)?;
846 crate::limits::Resolved::DEFAULT.check_input_size(text.len())?;
850 (fmt.read)(text)
851 }
852
853 pub fn to_format(&self, name: &str) -> Result<String, crate::error::OmnistError> {
856 let fmt = crate::registry::get_format(name)?;
857 (fmt.write)(self)
858 }
859
860 pub fn check_format(
867 &self,
868 name: &str,
869 ) -> Result<crate::report::WriteReport, crate::error::OmnistError> {
870 let fmt = crate::registry::get_format(name)?;
871 match &fmt.check {
872 Some(check) => Ok(check(self)),
873 None => Err(DocumentError::new(
874 "$",
875 format!("format {name:?} has no check() -- cannot simulate a write"),
876 )
877 .into()),
878 }
879 }
880}
881
882fn push_raw(arena: &mut Arena, node: RawNode, depth: usize) -> Result<NodeId, DocumentError> {
883 if depth > arena.limits.max_depth {
887 return Err(arena.limits.depth_error());
888 }
889 match node {
890 RawNode::Leaf(s) => {
891 if let Scalar::Int(i) = &s
892 && int_exceeds(i, arena.limits.max_int_digits)
893 {
894 return Err(arena.limits.int_digits_error("$"));
895 }
896 push(arena, NodeData::Leaf(s), depth, "$")
897 }
898 RawNode::Edges(edges) => {
899 let mut out: Vec<(String, NodeId)> = Vec::with_capacity(edges.len());
900 let mut rest = edges.into_iter();
901 while let Some((label, child)) = rest.next() {
902 match push_raw(arena, child, depth + 1) {
903 Ok(cid) => out.push((label, cid)),
904 Err(e) => {
905 return Err(splice_edge_path(e, &label, &out, rest.map(|(l, _)| l)));
906 }
907 }
908 }
909 push(arena, NodeData::Internal(out), depth, "$")
910 }
911 }
912}
913
914pub(crate) type RawEdge<'a> = (&'a str, Option<usize>, NodeId);
916
917fn with_occurrence_indices(
922 edges: &[(String, NodeId)],
923) -> impl Iterator<Item = (&str, Option<usize>, NodeId)> {
924 let mut counts: IndexMap<&str, (usize, usize)> = IndexMap::new();
925 for (label, _) in edges {
926 counts.entry(label.as_str()).or_insert((0, 0)).0 += 1;
927 }
928 edges.iter().map(move |(label, child)| {
929 let (total, seen) = counts
930 .get_mut(label.as_str())
931 .expect("every label was counted");
932 let index = crate::report::occurrence_index(*seen, *total);
933 *seen += 1;
934 (label.as_str(), index, *child)
935 })
936}
937
938fn splice_edge_path(
944 mut e: DocumentError,
945 label: &str,
946 done: &[(String, NodeId)],
947 after: impl Iterator<Item = String>,
948) -> DocumentError {
949 if e.code.as_deref() != Some("document.limit.int-digits") {
950 return e;
951 }
952 let before = done.iter().filter(|(l, _)| l == label).count();
953 let later = after.filter(|l| l == label).count();
954 let index = if before + later > 0 {
955 format!("[{before}]")
956 } else {
957 String::new()
958 };
959 e.path = format!("${}{index}{}", join("", label), &e.path[1..]);
960 e
961}
962
963#[cfg(test)]
964mod tests {
965 use super::*;
966
967 fn obj(pairs: &[(&str, Value)]) -> Value {
968 let mut m = IndexMap::new();
969 for (k, v) in pairs {
970 m.insert((*k).to_string(), v.clone());
971 }
972 Value::Object(m)
973 }
974
975 fn nest(levels: usize) -> Value {
979 let mut v = Value::Int((0).into());
980 for _ in 0..levels {
981 v = obj(&[("a", v)]);
982 }
983 v
984 }
985
986 #[test]
989 fn constructs_a_scalar_leaf() {
990 let doc = Doc::of(&Value::Int((42).into())).unwrap();
991 let root = doc.root();
992 assert!(root.is_leaf());
993 assert_eq!(root.value().unwrap(), &Scalar::Int((42).into()));
994 }
995
996 #[test]
997 fn constructs_an_object_as_ordered_edges() {
998 let v = obj(&[("b", Value::Int((1).into())), ("a", Value::Int((2).into()))]);
999 let doc = Doc::of(&v).unwrap();
1000 let root = doc.root();
1001 assert!(!root.is_leaf());
1002 let edges = root.edges().unwrap();
1003 let labels: Vec<&str> = edges.iter().map(|(l, _)| l.as_str()).collect();
1004 assert_eq!(labels, vec!["b", "a"]);
1006 }
1007
1008 #[test]
1009 fn a_list_value_expands_into_repeated_edges() {
1010 let v = obj(&[(
1011 "member",
1012 Value::Array(vec![
1013 Value::Int((1).into()),
1014 Value::Int((2).into()),
1015 Value::Int((3).into()),
1016 ]),
1017 )]);
1018 let doc = Doc::of(&v).unwrap();
1019 let root = doc.root();
1020 assert_eq!(root.count("member"), 3);
1021 let members = root.get("member");
1022 let vals: Vec<&Scalar> = members.iter().map(|c| c.value().unwrap()).collect();
1023 assert_eq!(
1024 vals,
1025 vec![
1026 &Scalar::Int((1).into()),
1027 &Scalar::Int((2).into()),
1028 &Scalar::Int((3).into())
1029 ]
1030 );
1031 }
1032
1033 #[test]
1034 fn a_bare_top_level_array_is_rejected() {
1035 let err = Doc::of(&Value::Array(vec![Value::Int((1).into())])).unwrap_err();
1036 assert!(err.message.contains("bare array"));
1037 assert_eq!(err.path, "$");
1038 }
1039
1040 #[test]
1041 fn an_array_of_arrays_is_rejected() {
1042 let v = obj(&[(
1043 "a",
1044 Value::Array(vec![Value::Array(vec![Value::Int((1).into())])]),
1045 )]);
1046 let err = Doc::of(&v).unwrap_err();
1047 assert!(err.message.contains("array of arrays"));
1048 assert_eq!(err.path, "$.a");
1050 let two = obj(&[(
1051 "a",
1052 Value::Array(vec![
1053 Value::Array(vec![Value::Int((1).into())]),
1054 Value::Array(vec![Value::Int((2).into())]),
1055 ]),
1056 )]);
1057 assert_eq!(Doc::of(&two).unwrap_err().path, "$.a[0]");
1058 }
1059
1060 #[test]
1063 fn depth_guard_accepts_exactly_max_depth() {
1064 let v = nest(MAX_DEPTH);
1067 assert!(Doc::of(&v).is_ok());
1068 }
1069
1070 #[test]
1071 fn depth_guard_rejects_one_past_max_depth() {
1072 let v = nest(MAX_DEPTH + 1);
1073 let err = Doc::of(&v).unwrap_err();
1074 assert!(err.message.contains("maximum depth"));
1075 }
1076
1077 fn wide(n: usize) -> Value {
1087 obj(&[(
1088 "a",
1089 Value::Array(vec![Value::Object(Default::default()); n]),
1090 )])
1091 }
1092
1093 #[test]
1094 fn node_guard_accepts_exactly_max_nodes() {
1095 let v = wide(MAX_NODES - 1);
1096 assert!(Doc::of(&v).is_ok());
1097 }
1098
1099 #[test]
1100 fn node_guard_rejects_one_past_max_nodes() {
1101 let v = wide(MAX_NODES);
1102 let err = Doc::of(&v).unwrap_err();
1103 assert!(err.message.contains("maximum node count"));
1104 }
1105
1106 #[test]
1107 fn an_array_value_consumes_an_extra_depth_level() {
1108 let direct = obj(&[("a", Value::Int((1).into()))]);
1115 let via_array = obj(&[("a", Value::Array(vec![Value::Int((1).into())]))]);
1116 let doc_direct = Doc::of(&direct).unwrap();
1117 let doc_array = Doc::of(&via_array).unwrap();
1118 let leaf_direct = doc_direct.root().child("a").unwrap();
1119 let leaf_array = doc_array.root().child("a").unwrap();
1120 assert_eq!(doc_direct.entry(leaf_direct.id()).depth, 1);
1121 assert_eq!(doc_array.entry(leaf_array.id()).depth, 2);
1122 }
1123
1124 #[test]
1127 fn every_tree_mutating_entry_point_enforces_the_depth_guard() {
1128 assert!(Doc::of(&nest(MAX_DEPTH + 1)).is_err());
1130
1131 let mut doc = Doc::of(&obj(&[("seed", Value::Int((0).into()))])).unwrap();
1134 let root_id = doc.root().id();
1135 let root_path = doc.root().path.clone();
1136 assert!(
1137 doc.add(root_id, &root_path, "b", &nest(MAX_DEPTH + 1))
1138 .is_err()
1139 );
1140
1141 let mut doc2 = Doc::of(&obj(&[("seed", Value::Int((0).into()))])).unwrap();
1143 let root_id2 = doc2.root().id();
1144 let root_path2 = doc2.root().path.clone();
1145 assert!(
1146 doc2.set(root_id2, &root_path2, "b", &nest(MAX_DEPTH + 1))
1147 .is_err()
1148 );
1149 }
1150
1151 #[test]
1155 fn add_at_a_deep_cursor_accounts_for_the_cursors_own_depth() {
1156 let mut doc = Doc::of(&nest(MAX_DEPTH)).unwrap();
1166 let mut cursor = doc.root();
1167 for _ in 0..190 {
1168 cursor = cursor.child("a").unwrap();
1169 }
1170 assert_eq!(doc.entry(cursor.id()).depth, 190);
1171 let id = cursor.id();
1172 let path = cursor.path.clone();
1173
1174 let too_deep = nest(15);
1175 assert!(doc.add(id, &path, "b", &too_deep).is_err());
1176
1177 let shallow = nest(5);
1181 assert!(doc.set(id, &path, "b", &shallow).is_ok());
1182 }
1183
1184 #[test]
1187 fn labels_and_get_preserve_first_seen_and_insertion_order() {
1188 let v = obj(&[
1192 (
1193 "z",
1194 Value::Array(vec![Value::Int((1).into()), Value::Int((3).into())]),
1195 ),
1196 ("a", Value::Int((2).into())),
1197 ("m", Value::Int((4).into())),
1198 ]);
1199 let doc = Doc::of(&v).unwrap();
1200 let root = doc.root();
1201 assert_eq!(root.labels(), vec!["z", "a", "m"]);
1202 let z_vals: Vec<&Scalar> = root.get("z").iter().map(|c| c.value().unwrap()).collect();
1203 assert_eq!(
1204 z_vals,
1205 vec![&Scalar::Int((1).into()), &Scalar::Int((3).into())]
1206 );
1207 }
1208
1209 #[test]
1210 fn labels_and_count_on_a_leaf_are_empty() {
1211 let doc = Doc::of(&Value::Int((1).into())).unwrap();
1212 let root = doc.root();
1213 assert!(root.labels().is_empty());
1214 assert_eq!(root.count("anything"), 0);
1215 }
1216
1217 #[test]
1218 fn to_grouped_preserves_first_seen_key_order() {
1219 let v = obj(&[
1220 (
1221 "z",
1222 Value::Array(vec![Value::Int((1).into()), Value::Int((3).into())]),
1223 ),
1224 ("a", Value::Int((2).into())),
1225 ]);
1226 let doc = Doc::of(&v).unwrap();
1227 let grouped = doc.to_grouped();
1228 let expected = obj(&[
1229 (
1230 "z",
1231 Value::Array(vec![Value::Int((1).into()), Value::Int((3).into())]),
1232 ),
1233 ("a", Value::Int((2).into())),
1234 ]);
1235 assert_eq!(grouped, expected);
1236 let keys: Vec<&str> = grouped
1239 .as_object()
1240 .unwrap()
1241 .keys()
1242 .map(|s| s.as_str())
1243 .collect();
1244 assert_eq!(keys, vec!["z", "a"]);
1245 }
1246
1247 #[test]
1248 fn value_as_object_is_none_for_a_non_object() {
1249 assert!(Value::Int((1).into()).as_object().is_none());
1250 }
1251
1252 #[test]
1255 fn add_appends_and_get_one_requires_exactly_one() {
1256 let mut doc = Doc::of(&obj(&[])).unwrap();
1257 let root_id = doc.root().id();
1258 let root_path = doc.root().path.clone();
1259 doc.add(root_id, &root_path, "x", &Value::Int((1).into()))
1260 .unwrap();
1261 doc.add(root_id, &root_path, "x", &Value::Int((2).into()))
1262 .unwrap();
1263 let root = doc.root();
1264 assert_eq!(root.count("x"), 2);
1265 assert!(root.get_one("x").is_err());
1266 }
1267
1268 #[test]
1269 fn set_replaces_all_occurrences_at_first_position() {
1270 let mut doc = Doc::of(&obj(&[
1271 ("x", Value::Int((1).into())),
1272 ("y", Value::Int((9).into())),
1273 ("x", Value::Int((2).into())),
1274 ]))
1275 .unwrap();
1276 let root_id = doc.root().id();
1277 let root_path = doc.root().path.clone();
1278 doc.set(root_id, &root_path, "x", &Value::Int((100).into()))
1279 .unwrap();
1280 let root = doc.root();
1281 let labels: Vec<String> = root.edges().unwrap().into_iter().map(|(l, _)| l).collect();
1282 assert_eq!(labels, vec!["x", "y"]);
1283 assert_eq!(
1284 root.get_one("x").unwrap().value().unwrap(),
1285 &Scalar::Int((100).into())
1286 );
1287 }
1288
1289 #[test]
1290 fn remove_drops_every_edge_with_that_label() {
1291 let mut doc = Doc::of(&obj(&[
1292 ("x", Value::Int((1).into())),
1293 ("x", Value::Int((2).into())),
1294 ]))
1295 .unwrap();
1296 let root_id = doc.root().id();
1297 let root_path = doc.root().path.clone();
1298 doc.remove(root_id, &root_path, "x").unwrap();
1299 assert_eq!(doc.root().count("x"), 0);
1300 }
1301
1302 #[test]
1303 fn internal_edges_mut_rejects_a_leaf_directly() {
1304 let mut doc = Doc::of(&Value::Int((1).into())).unwrap();
1309 let root_id = doc.root().id();
1310 let err = doc.internal_edges_mut(root_id, "$", "poke").unwrap_err();
1311 assert_eq!(err.path, "$");
1312 assert!(err.message.contains("cannot poke on a leaf"));
1313 }
1314
1315 #[test]
1316 fn mutation_on_a_leaf_is_rejected() {
1317 let mut doc = Doc::of(&Value::Int((1).into())).unwrap();
1318 let root_id = doc.root().id();
1319 let root_path = doc.root().path.clone();
1320 assert!(
1321 doc.add(root_id, &root_path, "x", &Value::Int((1).into()))
1322 .is_err()
1323 );
1324 assert!(
1325 doc.set(root_id, &root_path, "x", &Value::Int((1).into()))
1326 .is_err()
1327 );
1328 assert!(doc.remove(root_id, &root_path, "x").is_err());
1329 }
1330
1331 #[test]
1332 fn value_on_an_internal_node_is_rejected() {
1333 let doc = Doc::of(&obj(&[("x", Value::Int((1).into()))])).unwrap();
1334 assert!(doc.root().value().is_err());
1335 }
1336
1337 #[test]
1338 fn edges_on_a_leaf_is_rejected() {
1339 let doc = Doc::of(&Value::Int((1).into())).unwrap();
1340 assert!(doc.root().edges().is_err());
1341 }
1342
1343 #[test]
1344 fn raw_edges_on_a_leaf_is_rejected() {
1345 let doc = Doc::of(&Value::Int((1).into())).unwrap();
1348 assert!(doc.root().raw_edges().is_err());
1349 }
1350
1351 #[test]
1354 fn to_data_round_trips_structure() {
1355 let v = obj(&[
1356 ("a", Value::Int((1).into())),
1357 ("b", Value::Str("hi".to_string())),
1358 ]);
1359 let doc = Doc::of(&v).unwrap();
1360 assert_eq!(doc.to_data(), v);
1361 }
1362
1363 #[test]
1364 fn to_data_round_trips_every_scalar_variant() {
1365 let v = obj(&[
1369 ("n", Value::Null),
1370 ("b", Value::Bool(true)),
1371 ("i", Value::Int((7).into())),
1372 ("f", Value::Float(1.5)),
1373 ("s", Value::Str("hi".to_string())),
1374 ]);
1375 let doc = Doc::of(&v).unwrap();
1376 assert_eq!(doc.to_data(), v);
1377 assert_eq!(doc.to_grouped(), v);
1378 }
1379
1380 #[test]
1381 fn join_quotes_a_non_identifier_key() {
1382 let v = obj(&[(
1385 "1bad",
1386 Value::Array(vec![
1387 Value::Array(vec![Value::Int((1).into())]),
1388 Value::Array(vec![Value::Int((2).into())]),
1389 ]),
1390 )]);
1391 let err = Doc::of(&v).unwrap_err();
1392 assert_eq!(err.path, "$.1bad[0]");
1394 }
1395
1396 #[test]
1397 fn eq_doc_compares_structurally() {
1398 let a = Doc::of(&obj(&[("a", Value::Int((1).into()))])).unwrap();
1399 let b = Doc::of(&obj(&[("a", Value::Int((1).into()))])).unwrap();
1400 let c = Doc::of(&obj(&[("a", Value::Int((2).into()))])).unwrap();
1401 assert!(a.eq_doc(&b));
1402 assert!(!a.eq_doc(&c));
1403 }
1404
1405 #[test]
1406 fn eq_doc_is_false_when_shapes_differ() {
1407 let leaf = Doc::of(&Value::Int((1).into())).unwrap();
1410 let internal = Doc::of(&obj(&[("a", Value::Int((1).into()))])).unwrap();
1411 assert!(!leaf.eq_doc(&internal));
1412 assert!(!internal.eq_doc(&leaf));
1413 }
1414
1415 #[test]
1416 fn scalar_display_covers_every_variant() {
1417 assert_eq!(Scalar::Null.to_string(), "null");
1418 assert_eq!(Scalar::Bool(true).to_string(), "true");
1419 assert_eq!(Scalar::Int((1).into()).to_string(), "1");
1420 assert_eq!(Scalar::Float(1.5).to_string(), "1.5");
1421 assert_eq!(Scalar::Str("x".to_string()).to_string(), "\"x\"");
1422 }
1423
1424 #[test]
1427 fn from_raw_to_raw_round_trips_interleaved_repeated_labels() {
1428 let raw = RawNode::Edges(vec![
1432 ("b".to_string(), RawNode::Leaf(Scalar::Int((1).into()))),
1433 ("c".to_string(), RawNode::Leaf(Scalar::Int((2).into()))),
1434 ("b".to_string(), RawNode::Leaf(Scalar::Int((3).into()))),
1435 ]);
1436 let doc = Doc::from_raw(raw.clone()).unwrap();
1437 assert_eq!(doc.to_raw(), raw);
1438 let labels: Vec<String> = doc
1439 .root()
1440 .edges()
1441 .unwrap()
1442 .into_iter()
1443 .map(|(l, _)| l)
1444 .collect();
1445 assert_eq!(labels, vec!["b", "c", "b"]);
1446 }
1447
1448 #[test]
1449 fn from_raw_leaf_round_trips() {
1450 let raw = RawNode::Leaf(Scalar::Str("hi".to_string()));
1451 let doc = Doc::from_raw(raw.clone()).unwrap();
1452 assert!(doc.root().is_leaf());
1453 assert_eq!(doc.to_raw(), raw);
1454 }
1455
1456 #[test]
1457 fn from_raw_with_names_a_repeated_label_in_an_int_digits_path() {
1458 let leaf = |i: i64| RawNode::Leaf(Scalar::Int(i.into()));
1459 let limits = Limits::default().with_max_int_digits(3);
1460 let raw = RawNode::Edges(vec![("n".into(), leaf(1)), ("n".into(), leaf(1000))]);
1461 let e = Doc::from_raw_with(raw, &limits).unwrap_err();
1462 assert_eq!(e.path, "$.n[1]");
1463 let raw = RawNode::Edges(vec![("n".into(), leaf(1000)), ("n".into(), leaf(1))]);
1464 assert_eq!(Doc::from_raw_with(raw, &limits).unwrap_err().path, "$.n[0]");
1465 let raw = RawNode::Edges(vec![("n".into(), leaf(1000))]);
1466 assert_eq!(Doc::from_raw_with(raw, &limits).unwrap_err().path, "$.n");
1467 }
1468
1469 #[test]
1470 fn from_raw_enforces_the_depth_guard() {
1471 fn nest_raw(levels: usize) -> RawNode {
1472 let mut n = RawNode::Leaf(Scalar::Int((0).into()));
1473 for _ in 0..levels {
1474 n = RawNode::Edges(vec![("a".to_string(), n)]);
1475 }
1476 n
1477 }
1478 assert!(Doc::from_raw(nest_raw(MAX_DEPTH)).is_ok());
1479 let err = Doc::from_raw(nest_raw(MAX_DEPTH + 1)).unwrap_err();
1480 assert!(err.message.contains("maximum depth"));
1481 }
1482}