1use base64::{engine::general_purpose::STANDARD, Engine as _};
8use indexmap::IndexMap;
9use serde::{Deserialize, Deserializer, Serialize, Serializer};
10use std::fmt;
11
12use crate::error::{Error, Result};
13
14#[derive(Debug, Clone, PartialEq, Default)]
18pub enum Value {
19 #[default]
21 Null,
22 Bool(bool),
24 Integer(i64),
26 Float(f64),
28 String(String),
30 Bytes(Vec<u8>),
32 Sequence(Vec<Value>),
34 Mapping(IndexMap<String, Value>),
36}
37
38impl Serialize for Value {
40 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
41 where
42 S: Serializer,
43 {
44 match self {
45 Value::Null => serializer.serialize_none(),
46 Value::Bool(b) => serializer.serialize_bool(*b),
47 Value::Integer(i) => serializer.serialize_i64(*i),
48 Value::Float(f) => serializer.serialize_f64(*f),
49 Value::String(s) => serializer.serialize_str(s),
50 Value::Bytes(bytes) => {
51 let encoded = STANDARD.encode(bytes);
53 serializer.serialize_str(&encoded)
54 }
55 Value::Sequence(seq) => seq.serialize(serializer),
56 Value::Mapping(map) => map.serialize(serializer),
57 }
58 }
59}
60
61impl<'de> Deserialize<'de> for Value {
63 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
64 where
65 D: Deserializer<'de>,
66 {
67 #[derive(Deserialize)]
70 #[serde(untagged)]
71 enum ValueHelper {
72 Null,
73 Bool(bool),
74 Integer(i64),
75 Float(f64),
76 String(String),
77 Sequence(Vec<Value>),
78 Mapping(IndexMap<String, Value>),
79 }
80
81 match ValueHelper::deserialize(deserializer)? {
82 ValueHelper::Null => Ok(Value::Null),
83 ValueHelper::Bool(b) => Ok(Value::Bool(b)),
84 ValueHelper::Integer(i) => Ok(Value::Integer(i)),
85 ValueHelper::Float(f) => Ok(Value::Float(f)),
86 ValueHelper::String(s) => Ok(Value::String(s)),
87 ValueHelper::Sequence(seq) => Ok(Value::Sequence(seq)),
88 ValueHelper::Mapping(map) => Ok(Value::Mapping(map)),
89 }
90 }
91}
92
93impl Value {
94 pub fn is_null(&self) -> bool {
96 matches!(self, Value::Null)
97 }
98
99 pub fn is_bool(&self) -> bool {
101 matches!(self, Value::Bool(_))
102 }
103
104 pub fn is_integer(&self) -> bool {
106 matches!(self, Value::Integer(_))
107 }
108
109 pub fn is_float(&self) -> bool {
111 matches!(self, Value::Float(_))
112 }
113
114 pub fn is_string(&self) -> bool {
116 matches!(self, Value::String(_))
117 }
118
119 pub fn is_sequence(&self) -> bool {
121 matches!(self, Value::Sequence(_))
122 }
123
124 pub fn is_mapping(&self) -> bool {
126 matches!(self, Value::Mapping(_))
127 }
128
129 pub fn is_bytes(&self) -> bool {
131 matches!(self, Value::Bytes(_))
132 }
133
134 pub fn as_bool(&self) -> Option<bool> {
136 match self {
137 Value::Bool(b) => Some(*b),
138 _ => None,
139 }
140 }
141
142 pub fn as_i64(&self) -> Option<i64> {
144 match self {
145 Value::Integer(i) => Some(*i),
146 _ => None,
147 }
148 }
149
150 pub fn as_f64(&self) -> Option<f64> {
152 match self {
153 Value::Float(f) => Some(*f),
154 Value::Integer(i) => Some(*i as f64),
155 _ => None,
156 }
157 }
158
159 pub fn as_str(&self) -> Option<&str> {
161 match self {
162 Value::String(s) => Some(s),
163 _ => None,
164 }
165 }
166
167 pub fn as_sequence(&self) -> Option<&[Value]> {
169 match self {
170 Value::Sequence(s) => Some(s),
171 _ => None,
172 }
173 }
174
175 pub fn as_mapping(&self) -> Option<&IndexMap<String, Value>> {
177 match self {
178 Value::Mapping(m) => Some(m),
179 _ => None,
180 }
181 }
182
183 pub fn as_bytes(&self) -> Option<&[u8]> {
185 match self {
186 Value::Bytes(b) => Some(b),
187 _ => None,
188 }
189 }
190
191 pub fn get_path(&self, path: &str) -> Result<&Value> {
193 if path.is_empty() {
194 return Ok(self);
195 }
196
197 let segments = parse_path(path)?;
198 let mut current = self;
199
200 for segment in &segments {
201 current = match segment {
202 PathSegment::Key(key) => match current {
203 Value::Mapping(map) => map
204 .get(key.as_str())
205 .ok_or_else(|| Error::path_not_found(path))?,
206 _ => return Err(Error::path_not_found(path)),
207 },
208 PathSegment::Index(idx) => match current {
209 Value::Sequence(seq) => {
210 seq.get(*idx).ok_or_else(|| Error::path_not_found(path))?
211 }
212 _ => return Err(Error::path_not_found(path)),
213 },
214 };
215 }
216
217 Ok(current)
218 }
219
220 pub fn get_path_mut(&mut self, path: &str) -> Result<&mut Value> {
222 if path.is_empty() {
223 return Ok(self);
224 }
225
226 let segments = parse_path(path)?;
227 let mut current = self;
228
229 for segment in segments {
230 current = match segment {
231 PathSegment::Key(key) => match current {
232 Value::Mapping(map) => map
233 .get_mut(&key)
234 .ok_or_else(|| Error::path_not_found(path))?,
235 _ => return Err(Error::path_not_found(path)),
236 },
237 PathSegment::Index(idx) => match current {
238 Value::Sequence(seq) => seq
239 .get_mut(idx)
240 .ok_or_else(|| Error::path_not_found(path))?,
241 _ => return Err(Error::path_not_found(path)),
242 },
243 };
244 }
245
246 Ok(current)
247 }
248
249 pub fn set_path(&mut self, path: &str, value: Value) -> Result<()> {
251 if path.is_empty() {
252 *self = value;
253 return Ok(());
254 }
255
256 let segments = parse_path(path)?;
257 let mut current = self;
258
259 for (i, segment) in segments.iter().enumerate() {
260 let is_last = i == segments.len() - 1;
261
262 if is_last {
263 match segment {
264 PathSegment::Key(key) => {
265 if let Value::Mapping(map) = current {
266 map.insert(key.clone(), value);
267 return Ok(());
268 }
269 return Err(Error::path_not_found(path));
270 }
271 PathSegment::Index(idx) => {
272 if let Value::Sequence(seq) = current {
273 if *idx < seq.len() {
274 seq[*idx] = value;
275 return Ok(());
276 }
277 }
278 return Err(Error::path_not_found(path));
279 }
280 }
281 }
282
283 current = match segment {
285 PathSegment::Key(key) => {
286 if let Value::Mapping(map) = current {
287 let next_is_index = segments
289 .get(i + 1)
290 .map(|s| matches!(s, PathSegment::Index(_)))
291 .unwrap_or(false);
292
293 if !map.contains_key(key) {
294 let new_value = if next_is_index {
295 Value::Sequence(vec![])
296 } else {
297 Value::Mapping(IndexMap::new())
298 };
299 map.insert(key.clone(), new_value);
300 }
301 map.get_mut(key).unwrap()
302 } else {
303 return Err(Error::path_not_found(path));
304 }
305 }
306 PathSegment::Index(idx) => {
307 if let Value::Sequence(seq) = current {
308 seq.get_mut(*idx)
309 .ok_or_else(|| Error::path_not_found(path))?
310 } else {
311 return Err(Error::path_not_found(path));
312 }
313 }
314 };
315 }
316
317 Ok(())
318 }
319
320 pub fn type_name(&self) -> &'static str {
322 match self {
323 Value::Null => "null",
324 Value::Bool(_) => "boolean",
325 Value::Integer(_) => "integer",
326 Value::Float(_) => "float",
327 Value::String(_) => "string",
328 Value::Bytes(_) => "bytes",
329 Value::Sequence(_) => "sequence",
330 Value::Mapping(_) => "mapping",
331 }
332 }
333
334 pub fn merge(&mut self, other: Value) {
343 match (self, other) {
344 (Value::Mapping(base), Value::Mapping(overlay)) => {
346 for (key, overlay_value) in overlay {
347 if overlay_value.is_null() {
348 base.shift_remove(&key);
350 } else if let Some(base_value) = base.get_mut(&key) {
351 base_value.merge(overlay_value);
353 } else {
354 base.insert(key, overlay_value);
356 }
357 }
358 }
359 (this, other) => {
361 *this = other;
362 }
363 }
364 }
365
366 pub fn merged(mut self, other: Value) -> Value {
368 self.merge(other);
369 self
370 }
371
372 pub fn merge_tracking_sources(
377 &mut self,
378 other: Value,
379 source: &str,
380 path_prefix: &str,
381 sources: &mut std::collections::HashMap<String, String>,
382 ) {
383 match (self, other) {
384 (Value::Mapping(base), Value::Mapping(overlay)) => {
386 for (key, overlay_value) in overlay {
387 let full_path = if path_prefix.is_empty() {
388 key.clone()
389 } else {
390 format!("{}.{}", path_prefix, key)
391 };
392
393 if overlay_value.is_null() {
394 base.shift_remove(&key);
396 remove_sources_with_prefix(sources, &full_path);
397 } else if let Some(base_value) = base.get_mut(&key) {
398 base_value.merge_tracking_sources(
400 overlay_value,
401 source,
402 &full_path,
403 sources,
404 );
405 } else {
406 collect_leaf_paths(&overlay_value, &full_path, source, sources);
408 base.insert(key, overlay_value);
409 }
410 }
411 }
412 (this, other) => {
414 remove_sources_with_prefix(sources, path_prefix);
416 collect_leaf_paths(&other, path_prefix, source, sources);
418 *this = other;
419 }
420 }
421 }
422
423 pub fn collect_leaf_paths(
425 &self,
426 path_prefix: &str,
427 source: &str,
428 sources: &mut std::collections::HashMap<String, String>,
429 ) {
430 collect_leaf_paths(self, path_prefix, source, sources);
431 }
432}
433
434fn collect_leaf_paths(
436 value: &Value,
437 path_prefix: &str,
438 source: &str,
439 sources: &mut std::collections::HashMap<String, String>,
440) {
441 match value {
442 Value::Mapping(map) => {
443 for (key, val) in map {
444 let full_path = if path_prefix.is_empty() {
445 key.clone()
446 } else {
447 format!("{}.{}", path_prefix, key)
448 };
449 collect_leaf_paths(val, &full_path, source, sources);
450 }
451 }
452 Value::Sequence(seq) => {
453 for (i, val) in seq.iter().enumerate() {
454 let full_path = format!("{}[{}]", path_prefix, i);
455 collect_leaf_paths(val, &full_path, source, sources);
456 }
457 }
458 _ => {
460 if !path_prefix.is_empty() {
461 sources.insert(path_prefix.to_string(), source.to_string());
462 }
463 }
464 }
465}
466
467fn remove_sources_with_prefix(
469 sources: &mut std::collections::HashMap<String, String>,
470 prefix: &str,
471) {
472 if prefix.is_empty() {
473 sources.clear();
474 return;
475 }
476 sources.retain(|path, _| {
478 path != prefix
479 && !path.starts_with(&format!("{}.", prefix))
480 && !path.starts_with(&format!("{}[", prefix))
481 });
482}
483
484impl fmt::Display for Value {
485 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
486 match self {
487 Value::Null => write!(f, "null"),
488 Value::Bool(b) => write!(f, "{}", b),
489 Value::Integer(i) => write!(f, "{}", i),
490 Value::Float(n) => write!(f, "{}", n),
491 Value::String(s) => write!(f, "{}", s),
492 Value::Bytes(bytes) => write!(f, "<bytes: {} bytes>", bytes.len()),
493 Value::Sequence(seq) => {
494 write!(f, "[")?;
495 for (i, v) in seq.iter().enumerate() {
496 if i > 0 {
497 write!(f, ", ")?;
498 }
499 write!(f, "{}", v)?;
500 }
501 write!(f, "]")
502 }
503 Value::Mapping(map) => {
504 write!(f, "{{")?;
505 for (i, (k, v)) in map.iter().enumerate() {
506 if i > 0 {
507 write!(f, ", ")?;
508 }
509 write!(f, "{}: {}", k, v)?;
510 }
511 write!(f, "}}")
512 }
513 }
514 }
515}
516
517impl From<bool> for Value {
519 fn from(b: bool) -> Self {
520 Value::Bool(b)
521 }
522}
523
524impl From<i64> for Value {
525 fn from(i: i64) -> Self {
526 Value::Integer(i)
527 }
528}
529
530impl From<i32> for Value {
531 fn from(i: i32) -> Self {
532 Value::Integer(i as i64)
533 }
534}
535
536impl From<f64> for Value {
537 fn from(f: f64) -> Self {
538 Value::Float(f)
539 }
540}
541
542impl From<String> for Value {
543 fn from(s: String) -> Self {
544 Value::String(s)
545 }
546}
547
548impl From<&str> for Value {
549 fn from(s: &str) -> Self {
550 Value::String(s.to_string())
551 }
552}
553
554impl<T: Into<Value>> From<Vec<T>> for Value {
555 fn from(v: Vec<T>) -> Self {
556 Value::Sequence(v.into_iter().map(Into::into).collect())
557 }
558}
559
560impl From<IndexMap<String, Value>> for Value {
561 fn from(m: IndexMap<String, Value>) -> Self {
562 Value::Mapping(m)
563 }
564}
565
566impl From<Vec<u8>> for Value {
567 fn from(bytes: Vec<u8>) -> Self {
568 Value::Bytes(bytes)
569 }
570}
571
572#[derive(Debug, Clone, PartialEq)]
574enum PathSegment {
575 Key(String),
577 Index(usize),
579}
580
581fn parse_path(path: &str) -> Result<Vec<PathSegment>> {
584 let mut segments = Vec::new();
585 let mut current_key = String::new();
586 let mut chars = path.chars().peekable();
587
588 while let Some(c) = chars.next() {
589 match c {
590 '.' => {
591 if !current_key.is_empty() {
592 segments.push(PathSegment::Key(current_key.clone()));
593 current_key.clear();
594 }
595 }
596 '[' => {
597 if !current_key.is_empty() {
598 segments.push(PathSegment::Key(current_key.clone()));
599 current_key.clear();
600 }
601 let mut index_str = String::new();
603 while let Some(&c) = chars.peek() {
604 if c == ']' {
605 chars.next();
606 break;
607 }
608 index_str.push(chars.next().unwrap());
609 }
610 let idx: usize = index_str.parse().map_err(|_| {
611 Error::parse(format!("Invalid array index in path: {}", index_str))
612 })?;
613 segments.push(PathSegment::Index(idx));
614 }
615 ']' => {
616 return Err(Error::parse("Unexpected ']' in path"));
617 }
618 _ => {
619 current_key.push(c);
620 }
621 }
622 }
623
624 if !current_key.is_empty() {
625 segments.push(PathSegment::Key(current_key));
626 }
627
628 Ok(segments)
629}
630
631#[cfg(test)]
632mod tests {
633 use super::*;
634
635 #[test]
636 fn test_parse_simple_path() {
637 let segments = parse_path("database").unwrap();
638 assert_eq!(segments, vec![PathSegment::Key("database".into())]);
639 }
640
641 #[test]
642 fn test_parse_dotted_path() {
643 let segments = parse_path("database.host").unwrap();
644 assert_eq!(
645 segments,
646 vec![
647 PathSegment::Key("database".into()),
648 PathSegment::Key("host".into())
649 ]
650 );
651 }
652
653 #[test]
654 fn test_parse_array_path() {
655 let segments = parse_path("servers[0]").unwrap();
656 assert_eq!(
657 segments,
658 vec![PathSegment::Key("servers".into()), PathSegment::Index(0)]
659 );
660 }
661
662 #[test]
663 fn test_parse_complex_path() {
664 let segments = parse_path("servers[0].host").unwrap();
665 assert_eq!(
666 segments,
667 vec![
668 PathSegment::Key("servers".into()),
669 PathSegment::Index(0),
670 PathSegment::Key("host".into())
671 ]
672 );
673 }
674
675 #[test]
676 fn test_value_get_path() {
677 let mut map = IndexMap::new();
678 let mut db = IndexMap::new();
679 db.insert("host".into(), Value::String("localhost".into()));
680 db.insert("port".into(), Value::Integer(5432));
681 map.insert("database".into(), Value::Mapping(db));
682
683 let value = Value::Mapping(map);
684
685 assert_eq!(
686 value.get_path("database.host").unwrap().as_str(),
687 Some("localhost")
688 );
689 assert_eq!(
690 value.get_path("database.port").unwrap().as_i64(),
691 Some(5432)
692 );
693 }
694
695 #[test]
696 fn test_value_get_path_array() {
697 let mut map = IndexMap::new();
698 map.insert(
699 "servers".into(),
700 Value::Sequence(vec![
701 Value::String("server1".into()),
702 Value::String("server2".into()),
703 ]),
704 );
705
706 let value = Value::Mapping(map);
707
708 assert_eq!(
709 value.get_path("servers[0]").unwrap().as_str(),
710 Some("server1")
711 );
712 assert_eq!(
713 value.get_path("servers[1]").unwrap().as_str(),
714 Some("server2")
715 );
716 }
717
718 #[test]
719 fn test_value_get_path_not_found() {
720 let map = IndexMap::new();
721 let value = Value::Mapping(map);
722
723 assert!(value.get_path("nonexistent").is_err());
724 }
725
726 #[test]
727 fn test_value_type_checks() {
728 assert!(Value::Null.is_null());
729 assert!(Value::Bool(true).is_bool());
730 assert!(Value::Integer(42).is_integer());
731 assert!(Value::Float(2.5).is_float());
732 assert!(Value::String("hello".into()).is_string());
733 assert!(Value::Sequence(vec![]).is_sequence());
734 assert!(Value::Mapping(IndexMap::new()).is_mapping());
735 }
736
737 #[test]
738 fn test_value_conversions() {
739 assert_eq!(Value::Bool(true).as_bool(), Some(true));
740 assert_eq!(Value::Integer(42).as_i64(), Some(42));
741 assert_eq!(Value::Float(2.5).as_f64(), Some(2.5));
742 assert_eq!(Value::Integer(42).as_f64(), Some(42.0));
743 assert_eq!(Value::String("hello".into()).as_str(), Some("hello"));
744 }
745
746 #[test]
747 fn test_merge_scalars() {
748 let mut base = Value::String("base".into());
749 base.merge(Value::String("overlay".into()));
750 assert_eq!(base.as_str(), Some("overlay"));
751 }
752
753 #[test]
754 fn test_merge_deep() {
755 let mut db_base = IndexMap::new();
757 db_base.insert("host".into(), Value::String("localhost".into()));
758 db_base.insert("port".into(), Value::Integer(5432));
759 let mut base = IndexMap::new();
760 base.insert("database".into(), Value::Mapping(db_base));
761 let mut base = Value::Mapping(base);
762
763 let mut db_overlay = IndexMap::new();
765 db_overlay.insert("host".into(), Value::String("prod-db".into()));
766 let mut overlay = IndexMap::new();
767 overlay.insert("database".into(), Value::Mapping(db_overlay));
768 let overlay = Value::Mapping(overlay);
769
770 base.merge(overlay);
771
772 assert_eq!(
774 base.get_path("database.host").unwrap().as_str(),
775 Some("prod-db")
776 );
777 assert_eq!(base.get_path("database.port").unwrap().as_i64(), Some(5432));
778 }
779
780 #[test]
781 fn test_merge_null_removes_key() {
782 let mut feature = IndexMap::new();
784 feature.insert("enabled".into(), Value::Bool(true));
785 feature.insert("config".into(), Value::String("value".into()));
786 let mut base = IndexMap::new();
787 base.insert("feature".into(), Value::Mapping(feature));
788 let mut base = Value::Mapping(base);
789
790 let mut feature_overlay = IndexMap::new();
792 feature_overlay.insert("config".into(), Value::Null);
793 let mut overlay = IndexMap::new();
794 overlay.insert("feature".into(), Value::Mapping(feature_overlay));
795 let overlay = Value::Mapping(overlay);
796
797 base.merge(overlay);
798
799 assert_eq!(
801 base.get_path("feature.enabled").unwrap().as_bool(),
802 Some(true)
803 );
804 assert!(base.get_path("feature.config").is_err());
805 }
806
807 #[test]
808 fn test_merge_array_replaces() {
809 let mut base = IndexMap::new();
811 base.insert(
812 "servers".into(),
813 Value::Sequence(vec![Value::String("a".into()), Value::String("b".into())]),
814 );
815 let mut base = Value::Mapping(base);
816
817 let mut overlay = IndexMap::new();
819 overlay.insert(
820 "servers".into(),
821 Value::Sequence(vec![Value::String("c".into())]),
822 );
823 let overlay = Value::Mapping(overlay);
824
825 base.merge(overlay);
826
827 let servers = base.get_path("servers").unwrap().as_sequence().unwrap();
829 assert_eq!(servers.len(), 1);
830 assert_eq!(servers[0].as_str(), Some("c"));
831 }
832
833 #[test]
834 fn test_merge_type_mismatch() {
835 let mut db = IndexMap::new();
837 db.insert("host".into(), Value::String("localhost".into()));
838 let mut base = IndexMap::new();
839 base.insert("database".into(), Value::Mapping(db));
840 let mut base = Value::Mapping(base);
841
842 let mut overlay = IndexMap::new();
844 overlay.insert("database".into(), Value::String("connection-string".into()));
845 let overlay = Value::Mapping(overlay);
846
847 base.merge(overlay);
848
849 assert_eq!(
851 base.get_path("database").unwrap().as_str(),
852 Some("connection-string")
853 );
854 }
855
856 #[test]
857 fn test_merge_adds_new_keys() {
858 let mut base = IndexMap::new();
860 base.insert("a".into(), Value::Integer(1));
861 let mut base = Value::Mapping(base);
862
863 let mut overlay = IndexMap::new();
865 overlay.insert("b".into(), Value::Integer(2));
866 let overlay = Value::Mapping(overlay);
867
868 base.merge(overlay);
869
870 assert_eq!(base.get_path("a").unwrap().as_i64(), Some(1));
872 assert_eq!(base.get_path("b").unwrap().as_i64(), Some(2));
873 }
874
875 #[test]
878 fn test_from_i32() {
879 let v: Value = 42i32.into();
880 assert_eq!(v, Value::Integer(42));
881 }
882
883 #[test]
884 fn test_from_vec_values() {
885 let vec: Vec<Value> = vec![Value::Integer(1), Value::Integer(2)];
886 let v: Value = vec.into();
887 assert!(v.is_sequence());
888 assert_eq!(v.as_sequence().unwrap().len(), 2);
889 }
890
891 #[test]
892 fn test_from_vec_strings() {
893 let vec: Vec<&str> = vec!["a", "b", "c"];
894 let v: Value = vec.into();
895 assert!(v.is_sequence());
896 assert_eq!(v.as_sequence().unwrap().len(), 3);
897 }
898
899 #[test]
900 fn test_from_indexmap() {
901 let mut map = IndexMap::new();
902 map.insert("key".to_string(), Value::Integer(42));
903 let v: Value = map.into();
904 assert!(v.is_mapping());
905 }
906
907 #[test]
908 fn test_display_null() {
909 assert_eq!(format!("{}", Value::Null), "null");
910 }
911
912 #[test]
913 fn test_display_bool() {
914 assert_eq!(format!("{}", Value::Bool(true)), "true");
915 assert_eq!(format!("{}", Value::Bool(false)), "false");
916 }
917
918 #[test]
919 fn test_display_integer() {
920 assert_eq!(format!("{}", Value::Integer(42)), "42");
921 assert_eq!(format!("{}", Value::Integer(-123)), "-123");
922 }
923
924 #[test]
925 fn test_display_float() {
926 let display = format!("{}", Value::Float(1.5));
927 assert!(display.starts_with("1.5"));
928 }
929
930 #[test]
931 fn test_display_string() {
932 assert_eq!(format!("{}", Value::String("hello".into())), "hello");
933 }
934
935 #[test]
936 fn test_display_sequence() {
937 let seq = Value::Sequence(vec![
938 Value::Integer(1),
939 Value::Integer(2),
940 Value::Integer(3),
941 ]);
942 assert_eq!(format!("{}", seq), "[1, 2, 3]");
943 }
944
945 #[test]
946 fn test_display_empty_sequence() {
947 let seq = Value::Sequence(vec![]);
948 assert_eq!(format!("{}", seq), "[]");
949 }
950
951 #[test]
952 fn test_display_mapping() {
953 let mut map = IndexMap::new();
954 map.insert("a".to_string(), Value::Integer(1));
955 let mapping = Value::Mapping(map);
956 assert_eq!(format!("{}", mapping), "{a: 1}");
957 }
958
959 #[test]
960 fn test_display_empty_mapping() {
961 let mapping = Value::Mapping(IndexMap::new());
962 assert_eq!(format!("{}", mapping), "{}");
963 }
964
965 #[test]
966 fn test_as_str_non_string() {
967 assert!(Value::Integer(42).as_str().is_none());
968 assert!(Value::Bool(true).as_str().is_none());
969 assert!(Value::Null.as_str().is_none());
970 }
971
972 #[test]
973 fn test_as_bool_non_bool() {
974 assert!(Value::Integer(42).as_bool().is_none());
975 assert!(Value::String("true".into()).as_bool().is_none());
976 }
977
978 #[test]
979 fn test_as_i64_non_integer() {
980 assert!(Value::String("42".into()).as_i64().is_none());
981 assert!(Value::Float(42.0).as_i64().is_none());
982 }
983
984 #[test]
985 fn test_as_f64_non_numeric() {
986 assert!(Value::String("3.14".into()).as_f64().is_none());
987 assert!(Value::Bool(true).as_f64().is_none());
988 }
989
990 #[test]
991 fn test_as_sequence_non_sequence() {
992 assert!(Value::Integer(42).as_sequence().is_none());
993 assert!(Value::Mapping(IndexMap::new()).as_sequence().is_none());
994 }
995
996 #[test]
997 fn test_as_mapping_non_mapping() {
998 assert!(Value::Integer(42).as_mapping().is_none());
999 assert!(Value::Sequence(vec![]).as_mapping().is_none());
1000 }
1001
1002 #[test]
1003 fn test_type_name() {
1004 assert_eq!(Value::Null.type_name(), "null");
1005 assert_eq!(Value::Bool(true).type_name(), "boolean");
1006 assert_eq!(Value::Integer(42).type_name(), "integer");
1007 assert_eq!(Value::Float(1.23).type_name(), "float");
1008 assert_eq!(Value::String("s".into()).type_name(), "string");
1009 assert_eq!(Value::Sequence(vec![]).type_name(), "sequence");
1010 assert_eq!(Value::Mapping(IndexMap::new()).type_name(), "mapping");
1011 }
1012
1013 #[test]
1014 fn test_default() {
1015 let v: Value = Default::default();
1016 assert!(v.is_null());
1017 }
1018
1019 #[test]
1020 fn test_get_path_empty() {
1021 let v = Value::Integer(42);
1022 assert_eq!(v.get_path("").unwrap(), &Value::Integer(42));
1023 }
1024
1025 #[test]
1026 fn test_get_path_on_non_mapping() {
1027 let v = Value::Integer(42);
1028 assert!(v.get_path("key").is_err());
1029 }
1030
1031 #[test]
1032 fn test_get_path_array_out_of_bounds() {
1033 let mut map = IndexMap::new();
1034 map.insert(
1035 "items".to_string(),
1036 Value::Sequence(vec![Value::Integer(1)]),
1037 );
1038 let v = Value::Mapping(map);
1039 assert!(v.get_path("items[99]").is_err());
1040 }
1041
1042 #[test]
1043 fn test_get_path_array_on_non_sequence() {
1044 let mut map = IndexMap::new();
1045 map.insert("key".to_string(), Value::Integer(42));
1046 let v = Value::Mapping(map);
1047 assert!(v.get_path("key[0]").is_err());
1048 }
1049
1050 #[test]
1051 fn test_get_path_mut_empty() {
1052 let mut v = Value::Integer(42);
1053 let result = v.get_path_mut("").unwrap();
1054 *result = Value::Integer(100);
1055 assert_eq!(v, Value::Integer(100));
1056 }
1057
1058 #[test]
1059 fn test_get_path_mut_modify() {
1060 let mut map = IndexMap::new();
1061 map.insert("key".to_string(), Value::Integer(42));
1062 let mut v = Value::Mapping(map);
1063
1064 *v.get_path_mut("key").unwrap() = Value::Integer(100);
1065 assert_eq!(v.get_path("key").unwrap().as_i64(), Some(100));
1066 }
1067
1068 #[test]
1069 fn test_get_path_mut_not_found() {
1070 let mut map = IndexMap::new();
1071 map.insert("key".to_string(), Value::Integer(42));
1072 let mut v = Value::Mapping(map);
1073 assert!(v.get_path_mut("nonexistent").is_err());
1074 }
1075
1076 #[test]
1077 fn test_get_path_mut_on_non_mapping() {
1078 let mut v = Value::Integer(42);
1079 assert!(v.get_path_mut("key").is_err());
1080 }
1081
1082 #[test]
1083 fn test_get_path_mut_array() {
1084 let mut map = IndexMap::new();
1085 map.insert(
1086 "items".to_string(),
1087 Value::Sequence(vec![Value::Integer(1), Value::Integer(2)]),
1088 );
1089 let mut v = Value::Mapping(map);
1090
1091 *v.get_path_mut("items[1]").unwrap() = Value::Integer(99);
1092 assert_eq!(v.get_path("items[1]").unwrap().as_i64(), Some(99));
1093 }
1094
1095 #[test]
1096 fn test_get_path_mut_array_out_of_bounds() {
1097 let mut map = IndexMap::new();
1098 map.insert(
1099 "items".to_string(),
1100 Value::Sequence(vec![Value::Integer(1)]),
1101 );
1102 let mut v = Value::Mapping(map);
1103 assert!(v.get_path_mut("items[99]").is_err());
1104 }
1105
1106 #[test]
1107 fn test_get_path_mut_array_on_non_sequence() {
1108 let mut map = IndexMap::new();
1109 map.insert("key".to_string(), Value::Integer(42));
1110 let mut v = Value::Mapping(map);
1111 assert!(v.get_path_mut("key[0]").is_err());
1112 }
1113
1114 #[test]
1115 fn test_set_path_empty() {
1116 let mut v = Value::Integer(42);
1117 v.set_path("", Value::Integer(100)).unwrap();
1118 assert_eq!(v, Value::Integer(100));
1119 }
1120
1121 #[test]
1122 fn test_set_path_simple() {
1123 let mut map = IndexMap::new();
1124 map.insert("key".to_string(), Value::Integer(42));
1125 let mut v = Value::Mapping(map);
1126
1127 v.set_path("key", Value::Integer(100)).unwrap();
1128 assert_eq!(v.get_path("key").unwrap().as_i64(), Some(100));
1129 }
1130
1131 #[test]
1132 fn test_set_path_new_key() {
1133 let mut map = IndexMap::new();
1134 map.insert("existing".to_string(), Value::Integer(1));
1135 let mut v = Value::Mapping(map);
1136
1137 v.set_path("new_key", Value::Integer(42)).unwrap();
1138 assert_eq!(v.get_path("new_key").unwrap().as_i64(), Some(42));
1139 }
1140
1141 #[test]
1142 fn test_set_path_creates_intermediate_mappings() {
1143 let mut v = Value::Mapping(IndexMap::new());
1144 v.set_path("a.b.c", Value::Integer(42)).unwrap();
1145 assert_eq!(v.get_path("a.b.c").unwrap().as_i64(), Some(42));
1146 }
1147
1148 #[test]
1149 fn test_set_path_array_element() {
1150 let mut map = IndexMap::new();
1151 map.insert(
1152 "items".to_string(),
1153 Value::Sequence(vec![Value::Integer(1), Value::Integer(2)]),
1154 );
1155 let mut v = Value::Mapping(map);
1156
1157 v.set_path("items[0]", Value::Integer(99)).unwrap();
1158 assert_eq!(v.get_path("items[0]").unwrap().as_i64(), Some(99));
1159 }
1160
1161 #[test]
1162 fn test_set_path_array_out_of_bounds() {
1163 let mut map = IndexMap::new();
1164 map.insert(
1165 "items".to_string(),
1166 Value::Sequence(vec![Value::Integer(1)]),
1167 );
1168 let mut v = Value::Mapping(map);
1169 assert!(v.set_path("items[99]", Value::Integer(42)).is_err());
1170 }
1171
1172 #[test]
1173 fn test_set_path_on_non_mapping() {
1174 let mut v = Value::Integer(42);
1175 assert!(v.set_path("key", Value::Integer(1)).is_err());
1176 }
1177
1178 #[test]
1179 fn test_set_path_key_on_non_mapping_intermediate() {
1180 let mut map = IndexMap::new();
1181 map.insert("key".to_string(), Value::Integer(42));
1182 let mut v = Value::Mapping(map);
1183 assert!(v.set_path("key.subkey", Value::Integer(1)).is_err());
1185 }
1186
1187 #[test]
1188 fn test_set_path_index_on_non_sequence() {
1189 let mut map = IndexMap::new();
1190 map.insert("key".to_string(), Value::Integer(42));
1191 let mut v = Value::Mapping(map);
1192 assert!(v.set_path("key[0]", Value::Integer(1)).is_err());
1193 }
1194
1195 #[test]
1196 fn test_set_path_intermediate_index_out_of_bounds() {
1197 let mut map = IndexMap::new();
1198 map.insert(
1199 "items".to_string(),
1200 Value::Sequence(vec![Value::Mapping(IndexMap::new())]),
1201 );
1202 let mut v = Value::Mapping(map);
1203 assert!(v.set_path("items[99].key", Value::Integer(1)).is_err());
1204 }
1205
1206 #[test]
1207 fn test_merged_non_mutating() {
1208 let mut base_map = IndexMap::new();
1209 base_map.insert("a".to_string(), Value::Integer(1));
1210 let base = Value::Mapping(base_map);
1211
1212 let mut overlay_map = IndexMap::new();
1213 overlay_map.insert("b".to_string(), Value::Integer(2));
1214 let overlay = Value::Mapping(overlay_map);
1215
1216 let result = base.merged(overlay);
1217
1218 assert_eq!(result.get_path("a").unwrap().as_i64(), Some(1));
1219 assert_eq!(result.get_path("b").unwrap().as_i64(), Some(2));
1220 }
1221
1222 #[test]
1223 fn test_parse_path_invalid_index() {
1224 assert!(parse_path("items[abc]").is_err());
1225 }
1226
1227 #[test]
1228 fn test_parse_path_unexpected_bracket() {
1229 assert!(parse_path("items]").is_err());
1230 }
1231
1232 #[test]
1233 fn test_is_type_negative_cases() {
1234 let integer = Value::Integer(42);
1235 assert!(!integer.is_null());
1236 assert!(!integer.is_bool());
1237 assert!(!integer.is_float());
1238 assert!(!integer.is_string());
1239 assert!(!integer.is_sequence());
1240 assert!(!integer.is_mapping());
1241 assert!(!integer.is_bytes());
1242 }
1243
1244 #[test]
1247 fn test_bytes_is_bytes() {
1248 let bytes = Value::Bytes(vec![0x48, 0x65, 0x6c, 0x6c, 0x6f]); assert!(bytes.is_bytes());
1250 assert!(!bytes.is_string());
1251 assert!(!bytes.is_null());
1252 }
1253
1254 #[test]
1255 fn test_bytes_as_bytes() {
1256 let bytes = Value::Bytes(vec![1, 2, 3, 4, 5]);
1257 assert_eq!(bytes.as_bytes(), Some(&[1u8, 2, 3, 4, 5][..]));
1258 }
1259
1260 #[test]
1261 fn test_bytes_as_bytes_non_bytes() {
1262 assert!(Value::String("hello".into()).as_bytes().is_none());
1263 assert!(Value::Integer(42).as_bytes().is_none());
1264 }
1265
1266 #[test]
1267 fn test_bytes_type_name() {
1268 assert_eq!(Value::Bytes(vec![]).type_name(), "bytes");
1269 }
1270
1271 #[test]
1272 fn test_bytes_display() {
1273 let bytes = Value::Bytes(vec![1, 2, 3, 4, 5]);
1274 assert_eq!(format!("{}", bytes), "<bytes: 5 bytes>");
1275
1276 let empty = Value::Bytes(vec![]);
1277 assert_eq!(format!("{}", empty), "<bytes: 0 bytes>");
1278 }
1279
1280 #[test]
1281 fn test_bytes_from_vec() {
1282 let v: Value = vec![0x48u8, 0x65, 0x6c, 0x6c, 0x6f].into();
1283 assert!(v.is_bytes());
1284 assert_eq!(v.as_bytes(), Some(&[0x48u8, 0x65, 0x6c, 0x6c, 0x6f][..]));
1285 }
1286
1287 #[test]
1288 fn test_bytes_serialize_to_base64() {
1289 let bytes = Value::Bytes(vec![0x48, 0x65, 0x6c, 0x6c, 0x6f]); let yaml = serde_yaml::to_string(&bytes).unwrap();
1291 assert!(yaml.contains("SGVsbG8="));
1293 }
1294
1295 #[test]
1296 fn test_bytes_serialize_empty() {
1297 let bytes = Value::Bytes(vec![]);
1298 let json = serde_json::to_string(&bytes).unwrap();
1299 assert_eq!(json, "\"\"");
1301 }
1302
1303 #[test]
1304 fn test_bytes_equality() {
1305 let a = Value::Bytes(vec![1, 2, 3]);
1306 let b = Value::Bytes(vec![1, 2, 3]);
1307 let c = Value::Bytes(vec![1, 2, 4]);
1308
1309 assert_eq!(a, b);
1310 assert_ne!(a, c);
1311 }
1312
1313 #[test]
1314 fn test_bytes_clone() {
1315 let original = Value::Bytes(vec![1, 2, 3, 4, 5]);
1316 let cloned = original.clone();
1317 assert_eq!(original, cloned);
1318 }
1319}