1use indexmap::IndexMap;
8use serde::{Deserialize, Serialize};
9use std::fmt;
10
11use crate::error::{Error, Result};
12
13#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
15#[serde(untagged)]
16#[derive(Default)]
17pub enum Value {
18 #[default]
20 Null,
21 Bool(bool),
23 Integer(i64),
25 Float(f64),
27 String(String),
29 Sequence(Vec<Value>),
31 Mapping(IndexMap<String, Value>),
33}
34
35impl Value {
36 pub fn is_null(&self) -> bool {
38 matches!(self, Value::Null)
39 }
40
41 pub fn is_bool(&self) -> bool {
43 matches!(self, Value::Bool(_))
44 }
45
46 pub fn is_integer(&self) -> bool {
48 matches!(self, Value::Integer(_))
49 }
50
51 pub fn is_float(&self) -> bool {
53 matches!(self, Value::Float(_))
54 }
55
56 pub fn is_string(&self) -> bool {
58 matches!(self, Value::String(_))
59 }
60
61 pub fn is_sequence(&self) -> bool {
63 matches!(self, Value::Sequence(_))
64 }
65
66 pub fn is_mapping(&self) -> bool {
68 matches!(self, Value::Mapping(_))
69 }
70
71 pub fn as_bool(&self) -> Option<bool> {
73 match self {
74 Value::Bool(b) => Some(*b),
75 _ => None,
76 }
77 }
78
79 pub fn as_i64(&self) -> Option<i64> {
81 match self {
82 Value::Integer(i) => Some(*i),
83 _ => None,
84 }
85 }
86
87 pub fn as_f64(&self) -> Option<f64> {
89 match self {
90 Value::Float(f) => Some(*f),
91 Value::Integer(i) => Some(*i as f64),
92 _ => None,
93 }
94 }
95
96 pub fn as_str(&self) -> Option<&str> {
98 match self {
99 Value::String(s) => Some(s),
100 _ => None,
101 }
102 }
103
104 pub fn as_sequence(&self) -> Option<&[Value]> {
106 match self {
107 Value::Sequence(s) => Some(s),
108 _ => None,
109 }
110 }
111
112 pub fn as_mapping(&self) -> Option<&IndexMap<String, Value>> {
114 match self {
115 Value::Mapping(m) => Some(m),
116 _ => None,
117 }
118 }
119
120 pub fn get_path(&self, path: &str) -> Result<&Value> {
122 if path.is_empty() {
123 return Ok(self);
124 }
125
126 let segments = parse_path(path)?;
127 let mut current = self;
128
129 for segment in &segments {
130 current = match segment {
131 PathSegment::Key(key) => match current {
132 Value::Mapping(map) => map
133 .get(key.as_str())
134 .ok_or_else(|| Error::path_not_found(path))?,
135 _ => return Err(Error::path_not_found(path)),
136 },
137 PathSegment::Index(idx) => match current {
138 Value::Sequence(seq) => {
139 seq.get(*idx).ok_or_else(|| Error::path_not_found(path))?
140 }
141 _ => return Err(Error::path_not_found(path)),
142 },
143 };
144 }
145
146 Ok(current)
147 }
148
149 pub fn get_path_mut(&mut self, path: &str) -> Result<&mut Value> {
151 if path.is_empty() {
152 return Ok(self);
153 }
154
155 let segments = parse_path(path)?;
156 let mut current = self;
157
158 for segment in segments {
159 current = match segment {
160 PathSegment::Key(key) => match current {
161 Value::Mapping(map) => map
162 .get_mut(&key)
163 .ok_or_else(|| Error::path_not_found(path))?,
164 _ => return Err(Error::path_not_found(path)),
165 },
166 PathSegment::Index(idx) => match current {
167 Value::Sequence(seq) => seq
168 .get_mut(idx)
169 .ok_or_else(|| Error::path_not_found(path))?,
170 _ => return Err(Error::path_not_found(path)),
171 },
172 };
173 }
174
175 Ok(current)
176 }
177
178 pub fn set_path(&mut self, path: &str, value: Value) -> Result<()> {
180 if path.is_empty() {
181 *self = value;
182 return Ok(());
183 }
184
185 let segments = parse_path(path)?;
186 let mut current = self;
187
188 for (i, segment) in segments.iter().enumerate() {
189 let is_last = i == segments.len() - 1;
190
191 if is_last {
192 match segment {
193 PathSegment::Key(key) => {
194 if let Value::Mapping(map) = current {
195 map.insert(key.clone(), value);
196 return Ok(());
197 }
198 return Err(Error::path_not_found(path));
199 }
200 PathSegment::Index(idx) => {
201 if let Value::Sequence(seq) = current {
202 if *idx < seq.len() {
203 seq[*idx] = value;
204 return Ok(());
205 }
206 }
207 return Err(Error::path_not_found(path));
208 }
209 }
210 }
211
212 current = match segment {
214 PathSegment::Key(key) => {
215 if let Value::Mapping(map) = current {
216 let next_is_index = segments
218 .get(i + 1)
219 .map(|s| matches!(s, PathSegment::Index(_)))
220 .unwrap_or(false);
221
222 if !map.contains_key(key) {
223 let new_value = if next_is_index {
224 Value::Sequence(vec![])
225 } else {
226 Value::Mapping(IndexMap::new())
227 };
228 map.insert(key.clone(), new_value);
229 }
230 map.get_mut(key).unwrap()
231 } else {
232 return Err(Error::path_not_found(path));
233 }
234 }
235 PathSegment::Index(idx) => {
236 if let Value::Sequence(seq) = current {
237 seq.get_mut(*idx)
238 .ok_or_else(|| Error::path_not_found(path))?
239 } else {
240 return Err(Error::path_not_found(path));
241 }
242 }
243 };
244 }
245
246 Ok(())
247 }
248
249 pub fn type_name(&self) -> &'static str {
251 match self {
252 Value::Null => "null",
253 Value::Bool(_) => "boolean",
254 Value::Integer(_) => "integer",
255 Value::Float(_) => "float",
256 Value::String(_) => "string",
257 Value::Sequence(_) => "sequence",
258 Value::Mapping(_) => "mapping",
259 }
260 }
261
262 pub fn merge(&mut self, other: Value) {
271 match (self, other) {
272 (Value::Mapping(base), Value::Mapping(overlay)) => {
274 for (key, overlay_value) in overlay {
275 if overlay_value.is_null() {
276 base.shift_remove(&key);
278 } else if let Some(base_value) = base.get_mut(&key) {
279 base_value.merge(overlay_value);
281 } else {
282 base.insert(key, overlay_value);
284 }
285 }
286 }
287 (this, other) => {
289 *this = other;
290 }
291 }
292 }
293
294 pub fn merged(mut self, other: Value) -> Value {
296 self.merge(other);
297 self
298 }
299}
300
301impl fmt::Display for Value {
302 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
303 match self {
304 Value::Null => write!(f, "null"),
305 Value::Bool(b) => write!(f, "{}", b),
306 Value::Integer(i) => write!(f, "{}", i),
307 Value::Float(n) => write!(f, "{}", n),
308 Value::String(s) => write!(f, "{}", s),
309 Value::Sequence(seq) => {
310 write!(f, "[")?;
311 for (i, v) in seq.iter().enumerate() {
312 if i > 0 {
313 write!(f, ", ")?;
314 }
315 write!(f, "{}", v)?;
316 }
317 write!(f, "]")
318 }
319 Value::Mapping(map) => {
320 write!(f, "{{")?;
321 for (i, (k, v)) in map.iter().enumerate() {
322 if i > 0 {
323 write!(f, ", ")?;
324 }
325 write!(f, "{}: {}", k, v)?;
326 }
327 write!(f, "}}")
328 }
329 }
330 }
331}
332
333impl From<bool> for Value {
335 fn from(b: bool) -> Self {
336 Value::Bool(b)
337 }
338}
339
340impl From<i64> for Value {
341 fn from(i: i64) -> Self {
342 Value::Integer(i)
343 }
344}
345
346impl From<i32> for Value {
347 fn from(i: i32) -> Self {
348 Value::Integer(i as i64)
349 }
350}
351
352impl From<f64> for Value {
353 fn from(f: f64) -> Self {
354 Value::Float(f)
355 }
356}
357
358impl From<String> for Value {
359 fn from(s: String) -> Self {
360 Value::String(s)
361 }
362}
363
364impl From<&str> for Value {
365 fn from(s: &str) -> Self {
366 Value::String(s.to_string())
367 }
368}
369
370impl<T: Into<Value>> From<Vec<T>> for Value {
371 fn from(v: Vec<T>) -> Self {
372 Value::Sequence(v.into_iter().map(Into::into).collect())
373 }
374}
375
376impl From<IndexMap<String, Value>> for Value {
377 fn from(m: IndexMap<String, Value>) -> Self {
378 Value::Mapping(m)
379 }
380}
381
382#[derive(Debug, Clone, PartialEq)]
384enum PathSegment {
385 Key(String),
387 Index(usize),
389}
390
391fn parse_path(path: &str) -> Result<Vec<PathSegment>> {
394 let mut segments = Vec::new();
395 let mut current_key = String::new();
396 let mut chars = path.chars().peekable();
397
398 while let Some(c) = chars.next() {
399 match c {
400 '.' => {
401 if !current_key.is_empty() {
402 segments.push(PathSegment::Key(current_key.clone()));
403 current_key.clear();
404 }
405 }
406 '[' => {
407 if !current_key.is_empty() {
408 segments.push(PathSegment::Key(current_key.clone()));
409 current_key.clear();
410 }
411 let mut index_str = String::new();
413 while let Some(&c) = chars.peek() {
414 if c == ']' {
415 chars.next();
416 break;
417 }
418 index_str.push(chars.next().unwrap());
419 }
420 let idx: usize = index_str.parse().map_err(|_| {
421 Error::parse(format!("Invalid array index in path: {}", index_str))
422 })?;
423 segments.push(PathSegment::Index(idx));
424 }
425 ']' => {
426 return Err(Error::parse("Unexpected ']' in path"));
427 }
428 _ => {
429 current_key.push(c);
430 }
431 }
432 }
433
434 if !current_key.is_empty() {
435 segments.push(PathSegment::Key(current_key));
436 }
437
438 Ok(segments)
439}
440
441#[cfg(test)]
442mod tests {
443 use super::*;
444
445 #[test]
446 fn test_parse_simple_path() {
447 let segments = parse_path("database").unwrap();
448 assert_eq!(segments, vec![PathSegment::Key("database".into())]);
449 }
450
451 #[test]
452 fn test_parse_dotted_path() {
453 let segments = parse_path("database.host").unwrap();
454 assert_eq!(
455 segments,
456 vec![
457 PathSegment::Key("database".into()),
458 PathSegment::Key("host".into())
459 ]
460 );
461 }
462
463 #[test]
464 fn test_parse_array_path() {
465 let segments = parse_path("servers[0]").unwrap();
466 assert_eq!(
467 segments,
468 vec![PathSegment::Key("servers".into()), PathSegment::Index(0)]
469 );
470 }
471
472 #[test]
473 fn test_parse_complex_path() {
474 let segments = parse_path("servers[0].host").unwrap();
475 assert_eq!(
476 segments,
477 vec![
478 PathSegment::Key("servers".into()),
479 PathSegment::Index(0),
480 PathSegment::Key("host".into())
481 ]
482 );
483 }
484
485 #[test]
486 fn test_value_get_path() {
487 let mut map = IndexMap::new();
488 let mut db = IndexMap::new();
489 db.insert("host".into(), Value::String("localhost".into()));
490 db.insert("port".into(), Value::Integer(5432));
491 map.insert("database".into(), Value::Mapping(db));
492
493 let value = Value::Mapping(map);
494
495 assert_eq!(
496 value.get_path("database.host").unwrap().as_str(),
497 Some("localhost")
498 );
499 assert_eq!(
500 value.get_path("database.port").unwrap().as_i64(),
501 Some(5432)
502 );
503 }
504
505 #[test]
506 fn test_value_get_path_array() {
507 let mut map = IndexMap::new();
508 map.insert(
509 "servers".into(),
510 Value::Sequence(vec![
511 Value::String("server1".into()),
512 Value::String("server2".into()),
513 ]),
514 );
515
516 let value = Value::Mapping(map);
517
518 assert_eq!(
519 value.get_path("servers[0]").unwrap().as_str(),
520 Some("server1")
521 );
522 assert_eq!(
523 value.get_path("servers[1]").unwrap().as_str(),
524 Some("server2")
525 );
526 }
527
528 #[test]
529 fn test_value_get_path_not_found() {
530 let map = IndexMap::new();
531 let value = Value::Mapping(map);
532
533 assert!(value.get_path("nonexistent").is_err());
534 }
535
536 #[test]
537 fn test_value_type_checks() {
538 assert!(Value::Null.is_null());
539 assert!(Value::Bool(true).is_bool());
540 assert!(Value::Integer(42).is_integer());
541 assert!(Value::Float(2.5).is_float());
542 assert!(Value::String("hello".into()).is_string());
543 assert!(Value::Sequence(vec![]).is_sequence());
544 assert!(Value::Mapping(IndexMap::new()).is_mapping());
545 }
546
547 #[test]
548 fn test_value_conversions() {
549 assert_eq!(Value::Bool(true).as_bool(), Some(true));
550 assert_eq!(Value::Integer(42).as_i64(), Some(42));
551 assert_eq!(Value::Float(2.5).as_f64(), Some(2.5));
552 assert_eq!(Value::Integer(42).as_f64(), Some(42.0));
553 assert_eq!(Value::String("hello".into()).as_str(), Some("hello"));
554 }
555
556 #[test]
557 fn test_merge_scalars() {
558 let mut base = Value::String("base".into());
559 base.merge(Value::String("overlay".into()));
560 assert_eq!(base.as_str(), Some("overlay"));
561 }
562
563 #[test]
564 fn test_merge_deep() {
565 let mut db_base = IndexMap::new();
567 db_base.insert("host".into(), Value::String("localhost".into()));
568 db_base.insert("port".into(), Value::Integer(5432));
569 let mut base = IndexMap::new();
570 base.insert("database".into(), Value::Mapping(db_base));
571 let mut base = Value::Mapping(base);
572
573 let mut db_overlay = IndexMap::new();
575 db_overlay.insert("host".into(), Value::String("prod-db".into()));
576 let mut overlay = IndexMap::new();
577 overlay.insert("database".into(), Value::Mapping(db_overlay));
578 let overlay = Value::Mapping(overlay);
579
580 base.merge(overlay);
581
582 assert_eq!(
584 base.get_path("database.host").unwrap().as_str(),
585 Some("prod-db")
586 );
587 assert_eq!(base.get_path("database.port").unwrap().as_i64(), Some(5432));
588 }
589
590 #[test]
591 fn test_merge_null_removes_key() {
592 let mut feature = IndexMap::new();
594 feature.insert("enabled".into(), Value::Bool(true));
595 feature.insert("config".into(), Value::String("value".into()));
596 let mut base = IndexMap::new();
597 base.insert("feature".into(), Value::Mapping(feature));
598 let mut base = Value::Mapping(base);
599
600 let mut feature_overlay = IndexMap::new();
602 feature_overlay.insert("config".into(), Value::Null);
603 let mut overlay = IndexMap::new();
604 overlay.insert("feature".into(), Value::Mapping(feature_overlay));
605 let overlay = Value::Mapping(overlay);
606
607 base.merge(overlay);
608
609 assert_eq!(
611 base.get_path("feature.enabled").unwrap().as_bool(),
612 Some(true)
613 );
614 assert!(base.get_path("feature.config").is_err());
615 }
616
617 #[test]
618 fn test_merge_array_replaces() {
619 let mut base = IndexMap::new();
621 base.insert(
622 "servers".into(),
623 Value::Sequence(vec![Value::String("a".into()), Value::String("b".into())]),
624 );
625 let mut base = Value::Mapping(base);
626
627 let mut overlay = IndexMap::new();
629 overlay.insert(
630 "servers".into(),
631 Value::Sequence(vec![Value::String("c".into())]),
632 );
633 let overlay = Value::Mapping(overlay);
634
635 base.merge(overlay);
636
637 let servers = base.get_path("servers").unwrap().as_sequence().unwrap();
639 assert_eq!(servers.len(), 1);
640 assert_eq!(servers[0].as_str(), Some("c"));
641 }
642
643 #[test]
644 fn test_merge_type_mismatch() {
645 let mut db = IndexMap::new();
647 db.insert("host".into(), Value::String("localhost".into()));
648 let mut base = IndexMap::new();
649 base.insert("database".into(), Value::Mapping(db));
650 let mut base = Value::Mapping(base);
651
652 let mut overlay = IndexMap::new();
654 overlay.insert("database".into(), Value::String("connection-string".into()));
655 let overlay = Value::Mapping(overlay);
656
657 base.merge(overlay);
658
659 assert_eq!(
661 base.get_path("database").unwrap().as_str(),
662 Some("connection-string")
663 );
664 }
665
666 #[test]
667 fn test_merge_adds_new_keys() {
668 let mut base = IndexMap::new();
670 base.insert("a".into(), Value::Integer(1));
671 let mut base = Value::Mapping(base);
672
673 let mut overlay = IndexMap::new();
675 overlay.insert("b".into(), Value::Integer(2));
676 let overlay = Value::Mapping(overlay);
677
678 base.merge(overlay);
679
680 assert_eq!(base.get_path("a").unwrap().as_i64(), Some(1));
682 assert_eq!(base.get_path("b").unwrap().as_i64(), Some(2));
683 }
684
685 #[test]
688 fn test_from_i32() {
689 let v: Value = 42i32.into();
690 assert_eq!(v, Value::Integer(42));
691 }
692
693 #[test]
694 fn test_from_vec_values() {
695 let vec: Vec<Value> = vec![Value::Integer(1), Value::Integer(2)];
696 let v: Value = vec.into();
697 assert!(v.is_sequence());
698 assert_eq!(v.as_sequence().unwrap().len(), 2);
699 }
700
701 #[test]
702 fn test_from_vec_strings() {
703 let vec: Vec<&str> = vec!["a", "b", "c"];
704 let v: Value = vec.into();
705 assert!(v.is_sequence());
706 assert_eq!(v.as_sequence().unwrap().len(), 3);
707 }
708
709 #[test]
710 fn test_from_indexmap() {
711 let mut map = IndexMap::new();
712 map.insert("key".to_string(), Value::Integer(42));
713 let v: Value = map.into();
714 assert!(v.is_mapping());
715 }
716
717 #[test]
718 fn test_display_null() {
719 assert_eq!(format!("{}", Value::Null), "null");
720 }
721
722 #[test]
723 fn test_display_bool() {
724 assert_eq!(format!("{}", Value::Bool(true)), "true");
725 assert_eq!(format!("{}", Value::Bool(false)), "false");
726 }
727
728 #[test]
729 fn test_display_integer() {
730 assert_eq!(format!("{}", Value::Integer(42)), "42");
731 assert_eq!(format!("{}", Value::Integer(-123)), "-123");
732 }
733
734 #[test]
735 fn test_display_float() {
736 let display = format!("{}", Value::Float(1.5));
737 assert!(display.starts_with("1.5"));
738 }
739
740 #[test]
741 fn test_display_string() {
742 assert_eq!(format!("{}", Value::String("hello".into())), "hello");
743 }
744
745 #[test]
746 fn test_display_sequence() {
747 let seq = Value::Sequence(vec![
748 Value::Integer(1),
749 Value::Integer(2),
750 Value::Integer(3),
751 ]);
752 assert_eq!(format!("{}", seq), "[1, 2, 3]");
753 }
754
755 #[test]
756 fn test_display_empty_sequence() {
757 let seq = Value::Sequence(vec![]);
758 assert_eq!(format!("{}", seq), "[]");
759 }
760
761 #[test]
762 fn test_display_mapping() {
763 let mut map = IndexMap::new();
764 map.insert("a".to_string(), Value::Integer(1));
765 let mapping = Value::Mapping(map);
766 assert_eq!(format!("{}", mapping), "{a: 1}");
767 }
768
769 #[test]
770 fn test_display_empty_mapping() {
771 let mapping = Value::Mapping(IndexMap::new());
772 assert_eq!(format!("{}", mapping), "{}");
773 }
774
775 #[test]
776 fn test_as_str_non_string() {
777 assert!(Value::Integer(42).as_str().is_none());
778 assert!(Value::Bool(true).as_str().is_none());
779 assert!(Value::Null.as_str().is_none());
780 }
781
782 #[test]
783 fn test_as_bool_non_bool() {
784 assert!(Value::Integer(42).as_bool().is_none());
785 assert!(Value::String("true".into()).as_bool().is_none());
786 }
787
788 #[test]
789 fn test_as_i64_non_integer() {
790 assert!(Value::String("42".into()).as_i64().is_none());
791 assert!(Value::Float(42.0).as_i64().is_none());
792 }
793
794 #[test]
795 fn test_as_f64_non_numeric() {
796 assert!(Value::String("3.14".into()).as_f64().is_none());
797 assert!(Value::Bool(true).as_f64().is_none());
798 }
799
800 #[test]
801 fn test_as_sequence_non_sequence() {
802 assert!(Value::Integer(42).as_sequence().is_none());
803 assert!(Value::Mapping(IndexMap::new()).as_sequence().is_none());
804 }
805
806 #[test]
807 fn test_as_mapping_non_mapping() {
808 assert!(Value::Integer(42).as_mapping().is_none());
809 assert!(Value::Sequence(vec![]).as_mapping().is_none());
810 }
811
812 #[test]
813 fn test_type_name() {
814 assert_eq!(Value::Null.type_name(), "null");
815 assert_eq!(Value::Bool(true).type_name(), "boolean");
816 assert_eq!(Value::Integer(42).type_name(), "integer");
817 assert_eq!(Value::Float(1.23).type_name(), "float");
818 assert_eq!(Value::String("s".into()).type_name(), "string");
819 assert_eq!(Value::Sequence(vec![]).type_name(), "sequence");
820 assert_eq!(Value::Mapping(IndexMap::new()).type_name(), "mapping");
821 }
822
823 #[test]
824 fn test_default() {
825 let v: Value = Default::default();
826 assert!(v.is_null());
827 }
828
829 #[test]
830 fn test_get_path_empty() {
831 let v = Value::Integer(42);
832 assert_eq!(v.get_path("").unwrap(), &Value::Integer(42));
833 }
834
835 #[test]
836 fn test_get_path_on_non_mapping() {
837 let v = Value::Integer(42);
838 assert!(v.get_path("key").is_err());
839 }
840
841 #[test]
842 fn test_get_path_array_out_of_bounds() {
843 let mut map = IndexMap::new();
844 map.insert(
845 "items".to_string(),
846 Value::Sequence(vec![Value::Integer(1)]),
847 );
848 let v = Value::Mapping(map);
849 assert!(v.get_path("items[99]").is_err());
850 }
851
852 #[test]
853 fn test_get_path_array_on_non_sequence() {
854 let mut map = IndexMap::new();
855 map.insert("key".to_string(), Value::Integer(42));
856 let v = Value::Mapping(map);
857 assert!(v.get_path("key[0]").is_err());
858 }
859
860 #[test]
861 fn test_get_path_mut_empty() {
862 let mut v = Value::Integer(42);
863 let result = v.get_path_mut("").unwrap();
864 *result = Value::Integer(100);
865 assert_eq!(v, Value::Integer(100));
866 }
867
868 #[test]
869 fn test_get_path_mut_modify() {
870 let mut map = IndexMap::new();
871 map.insert("key".to_string(), Value::Integer(42));
872 let mut v = Value::Mapping(map);
873
874 *v.get_path_mut("key").unwrap() = Value::Integer(100);
875 assert_eq!(v.get_path("key").unwrap().as_i64(), Some(100));
876 }
877
878 #[test]
879 fn test_get_path_mut_not_found() {
880 let mut map = IndexMap::new();
881 map.insert("key".to_string(), Value::Integer(42));
882 let mut v = Value::Mapping(map);
883 assert!(v.get_path_mut("nonexistent").is_err());
884 }
885
886 #[test]
887 fn test_get_path_mut_on_non_mapping() {
888 let mut v = Value::Integer(42);
889 assert!(v.get_path_mut("key").is_err());
890 }
891
892 #[test]
893 fn test_get_path_mut_array() {
894 let mut map = IndexMap::new();
895 map.insert(
896 "items".to_string(),
897 Value::Sequence(vec![Value::Integer(1), Value::Integer(2)]),
898 );
899 let mut v = Value::Mapping(map);
900
901 *v.get_path_mut("items[1]").unwrap() = Value::Integer(99);
902 assert_eq!(v.get_path("items[1]").unwrap().as_i64(), Some(99));
903 }
904
905 #[test]
906 fn test_get_path_mut_array_out_of_bounds() {
907 let mut map = IndexMap::new();
908 map.insert(
909 "items".to_string(),
910 Value::Sequence(vec![Value::Integer(1)]),
911 );
912 let mut v = Value::Mapping(map);
913 assert!(v.get_path_mut("items[99]").is_err());
914 }
915
916 #[test]
917 fn test_get_path_mut_array_on_non_sequence() {
918 let mut map = IndexMap::new();
919 map.insert("key".to_string(), Value::Integer(42));
920 let mut v = Value::Mapping(map);
921 assert!(v.get_path_mut("key[0]").is_err());
922 }
923
924 #[test]
925 fn test_set_path_empty() {
926 let mut v = Value::Integer(42);
927 v.set_path("", Value::Integer(100)).unwrap();
928 assert_eq!(v, Value::Integer(100));
929 }
930
931 #[test]
932 fn test_set_path_simple() {
933 let mut map = IndexMap::new();
934 map.insert("key".to_string(), Value::Integer(42));
935 let mut v = Value::Mapping(map);
936
937 v.set_path("key", Value::Integer(100)).unwrap();
938 assert_eq!(v.get_path("key").unwrap().as_i64(), Some(100));
939 }
940
941 #[test]
942 fn test_set_path_new_key() {
943 let mut map = IndexMap::new();
944 map.insert("existing".to_string(), Value::Integer(1));
945 let mut v = Value::Mapping(map);
946
947 v.set_path("new_key", Value::Integer(42)).unwrap();
948 assert_eq!(v.get_path("new_key").unwrap().as_i64(), Some(42));
949 }
950
951 #[test]
952 fn test_set_path_creates_intermediate_mappings() {
953 let mut v = Value::Mapping(IndexMap::new());
954 v.set_path("a.b.c", Value::Integer(42)).unwrap();
955 assert_eq!(v.get_path("a.b.c").unwrap().as_i64(), Some(42));
956 }
957
958 #[test]
959 fn test_set_path_array_element() {
960 let mut map = IndexMap::new();
961 map.insert(
962 "items".to_string(),
963 Value::Sequence(vec![Value::Integer(1), Value::Integer(2)]),
964 );
965 let mut v = Value::Mapping(map);
966
967 v.set_path("items[0]", Value::Integer(99)).unwrap();
968 assert_eq!(v.get_path("items[0]").unwrap().as_i64(), Some(99));
969 }
970
971 #[test]
972 fn test_set_path_array_out_of_bounds() {
973 let mut map = IndexMap::new();
974 map.insert(
975 "items".to_string(),
976 Value::Sequence(vec![Value::Integer(1)]),
977 );
978 let mut v = Value::Mapping(map);
979 assert!(v.set_path("items[99]", Value::Integer(42)).is_err());
980 }
981
982 #[test]
983 fn test_set_path_on_non_mapping() {
984 let mut v = Value::Integer(42);
985 assert!(v.set_path("key", Value::Integer(1)).is_err());
986 }
987
988 #[test]
989 fn test_set_path_key_on_non_mapping_intermediate() {
990 let mut map = IndexMap::new();
991 map.insert("key".to_string(), Value::Integer(42));
992 let mut v = Value::Mapping(map);
993 assert!(v.set_path("key.subkey", Value::Integer(1)).is_err());
995 }
996
997 #[test]
998 fn test_set_path_index_on_non_sequence() {
999 let mut map = IndexMap::new();
1000 map.insert("key".to_string(), Value::Integer(42));
1001 let mut v = Value::Mapping(map);
1002 assert!(v.set_path("key[0]", Value::Integer(1)).is_err());
1003 }
1004
1005 #[test]
1006 fn test_set_path_intermediate_index_out_of_bounds() {
1007 let mut map = IndexMap::new();
1008 map.insert(
1009 "items".to_string(),
1010 Value::Sequence(vec![Value::Mapping(IndexMap::new())]),
1011 );
1012 let mut v = Value::Mapping(map);
1013 assert!(v.set_path("items[99].key", Value::Integer(1)).is_err());
1014 }
1015
1016 #[test]
1017 fn test_merged_non_mutating() {
1018 let mut base_map = IndexMap::new();
1019 base_map.insert("a".to_string(), Value::Integer(1));
1020 let base = Value::Mapping(base_map);
1021
1022 let mut overlay_map = IndexMap::new();
1023 overlay_map.insert("b".to_string(), Value::Integer(2));
1024 let overlay = Value::Mapping(overlay_map);
1025
1026 let result = base.merged(overlay);
1027
1028 assert_eq!(result.get_path("a").unwrap().as_i64(), Some(1));
1029 assert_eq!(result.get_path("b").unwrap().as_i64(), Some(2));
1030 }
1031
1032 #[test]
1033 fn test_parse_path_invalid_index() {
1034 assert!(parse_path("items[abc]").is_err());
1035 }
1036
1037 #[test]
1038 fn test_parse_path_unexpected_bracket() {
1039 assert!(parse_path("items]").is_err());
1040 }
1041
1042 #[test]
1043 fn test_is_type_negative_cases() {
1044 let integer = Value::Integer(42);
1045 assert!(!integer.is_null());
1046 assert!(!integer.is_bool());
1047 assert!(!integer.is_float());
1048 assert!(!integer.is_string());
1049 assert!(!integer.is_sequence());
1050 assert!(!integer.is_mapping());
1051 }
1052}