1use crate::de::{set_list_context, take_list_context};
7use crate::error::{Error, ErrorKind, Result};
8use crate::ser::{escape_str_into, write_f64};
9use indexmap::IndexMap;
10use serde::de::{self, Deserialize, Deserializer, IntoDeserializer, MapAccess, SeqAccess, Visitor};
11use serde::ser::{Serialize, SerializeMap, SerializeSeq, Serializer};
12use std::fmt;
13use std::ops::Index;
14use std::path::Path;
15
16#[derive(Debug, Clone, PartialEq)]
38pub enum Value {
39 Bool(bool),
41
42 Integer(i32),
44
45 Integer64(i64),
47
48 Float(f64),
50
51 String(String),
53
54 Array(Vec<Value>),
56
57 List(Vec<Value>),
59
60 Group(Map),
62}
63
64pub type Map = IndexMap<String, Value>;
67
68#[derive(Debug, Clone, PartialEq)]
70enum PathSegment<'a> {
71 Key(&'a str),
73 Index(usize),
75}
76
77fn parse_path(path: &str) -> Option<Vec<PathSegment<'_>>> {
86 if path.is_empty() {
87 return None;
88 }
89
90 let mut segments = Vec::new();
91 for part in path.split('.') {
92 if part.is_empty() {
93 return None;
94 }
95
96 if part.starts_with('[') && part.ends_with(']') {
97 let inner = &part[1..part.len() - 1];
98 let index: usize = inner.parse().ok()?;
99 segments.push(PathSegment::Index(index));
100 } else if let Ok(index) = part.parse::<usize>() {
101 segments.push(PathSegment::Index(index));
102 } else {
103 segments.push(PathSegment::Key(part));
104 }
105 }
106
107 if segments.is_empty() {
108 None
109 } else {
110 Some(segments)
111 }
112}
113
114impl Value {
115 pub fn is_bool(&self) -> bool {
117 matches!(self, Value::Bool(_))
118 }
119
120 pub fn is_integer(&self) -> bool {
122 matches!(self, Value::Integer(_) | Value::Integer64(_))
123 }
124
125 pub fn is_i32(&self) -> bool {
127 matches!(self, Value::Integer(_))
128 }
129
130 pub fn is_i64(&self) -> bool {
132 matches!(self, Value::Integer64(_))
133 }
134
135 pub fn is_float(&self) -> bool {
137 matches!(self, Value::Float(_))
138 }
139
140 pub fn is_number(&self) -> bool {
142 matches!(
143 self,
144 Value::Integer(_) | Value::Integer64(_) | Value::Float(_)
145 )
146 }
147
148 pub fn is_string(&self) -> bool {
150 matches!(self, Value::String(_))
151 }
152
153 pub fn is_array(&self) -> bool {
155 matches!(self, Value::Array(_))
156 }
157
158 pub fn is_list(&self) -> bool {
160 matches!(self, Value::List(_))
161 }
162
163 pub fn is_group(&self) -> bool {
165 matches!(self, Value::Group(_))
166 }
167
168 pub fn as_bool(&self) -> Option<bool> {
170 match self {
171 Value::Bool(b) => Some(*b),
172 _ => None,
173 }
174 }
175
176 pub fn as_i32(&self) -> Option<i32> {
178 match self {
179 Value::Integer(i) => Some(*i),
180 Value::Integer64(i) if *i >= i32::MIN as i64 && *i <= i32::MAX as i64 => {
181 Some(*i as i32)
182 }
183 _ => None,
184 }
185 }
186
187 pub fn as_i64(&self) -> Option<i64> {
189 match self {
190 Value::Integer(i) => Some(*i as i64),
191 Value::Integer64(i) => Some(*i),
192 _ => None,
193 }
194 }
195
196 pub fn as_f64(&self) -> Option<f64> {
200 match self {
201 Value::Float(f) => Some(*f),
202 Value::Integer(i) => Some(*i as f64),
203 Value::Integer64(i) => Some(*i as f64),
204 _ => None,
205 }
206 }
207
208 pub fn as_str(&self) -> Option<&str> {
210 match self {
211 Value::String(s) => Some(s),
212 _ => None,
213 }
214 }
215
216 pub fn as_array(&self) -> Option<&Vec<Value>> {
220 match self {
221 Value::Array(arr) | Value::List(arr) => Some(arr),
222 _ => None,
223 }
224 }
225
226 pub fn as_array_mut(&mut self) -> Option<&mut Vec<Value>> {
229 match self {
230 Value::Array(arr) | Value::List(arr) => Some(arr),
231 _ => None,
232 }
233 }
234
235 pub fn as_group(&self) -> Option<&Map> {
237 match self {
238 Value::Group(map) => Some(map),
239 _ => None,
240 }
241 }
242
243 pub fn as_group_mut(&mut self) -> Option<&mut Map> {
250 match self {
251 Value::Group(map) => Some(map),
252 _ => None,
253 }
254 }
255
256 pub fn get<S: AsRef<str>>(&self, key: S) -> Option<&Value> {
260 match self {
261 Value::Group(map) => map.get(key.as_ref()),
262 _ => None,
263 }
264 }
265
266 pub fn get_mut<S: AsRef<str>>(&mut self, key: S) -> Option<&mut Value> {
270 match self {
271 Value::Group(map) => map.get_mut(key.as_ref()),
272 _ => None,
273 }
274 }
275
276 pub fn get_index(&self, index: usize) -> Option<&Value> {
280 match self {
281 Value::Array(arr) | Value::List(arr) => arr.get(index),
282 _ => None,
283 }
284 }
285
286 pub fn get_index_mut(&mut self, index: usize) -> Option<&mut Value> {
290 match self {
291 Value::Array(arr) | Value::List(arr) => arr.get_mut(index),
292 _ => None,
293 }
294 }
295
296 pub fn lookup(&self, path: &str) -> Option<&Value> {
317 let segments = parse_path(path)?;
318 let mut current = self;
319 for segment in &segments {
320 match segment {
321 PathSegment::Key(key) => current = current.get(*key)?,
322 PathSegment::Index(index) => current = current.get_index(*index)?,
323 }
324 }
325 Some(current)
326 }
327
328 pub fn lookup_mut(&mut self, path: &str) -> Option<&mut Value> {
347 let segments = parse_path(path)?;
348 let mut current = self;
349 for segment in &segments {
350 match segment {
351 PathSegment::Key(key) => match current {
352 Value::Group(map) => current = map.get_mut(*key)?,
353 _ => return None,
354 },
355 PathSegment::Index(index) => match current {
356 Value::Array(arr) | Value::List(arr) => current = arr.get_mut(*index)?,
357 _ => return None,
358 },
359 }
360 }
361 Some(current)
362 }
363
364 pub fn set(&mut self, path: &str, value: impl Into<Value>) -> Result<()> {
388 let segments = parse_path(path)
389 .ok_or_else(|| Error::from(ErrorKind::InvalidPath(path.to_string())))?;
390
391 for segment in &segments {
394 if let PathSegment::Key(key) = segment {
395 if !crate::ser::is_valid_name(key) {
396 return Err(ErrorKind::InvalidSettingName(key.to_string()).into());
397 }
398 }
399 }
400
401 let mut current = self;
402
403 for segment in &segments[..segments.len() - 1] {
405 match segment {
406 PathSegment::Key(key) => match current {
407 Value::Group(map) => {
408 current = map
409 .entry(key.to_string())
410 .or_insert_with(|| Value::Group(IndexMap::new()));
411 }
412 _ => {
413 return Err(ErrorKind::PathTraversal(format!(
414 "'{}' in '{}' is not a group",
415 key, path
416 ))
417 .into());
418 }
419 },
420 PathSegment::Index(index) => match current {
421 Value::Array(arr) | Value::List(arr) => {
422 let len = arr.len();
423 current = arr.get_mut(*index).ok_or_else(|| {
424 Error::from(ErrorKind::PathTraversal(format!(
425 "index {} out of bounds (length {}) in '{}'",
426 index, len, path
427 )))
428 })?;
429 }
430 _ => {
431 return Err(ErrorKind::PathTraversal(format!(
432 "cannot index into a non-array value in '{}'",
433 path
434 ))
435 .into());
436 }
437 },
438 }
439 }
440
441 match segments.last().unwrap() {
443 PathSegment::Key(key) => match current {
444 Value::Group(map) => {
445 map.insert(key.to_string(), value.into());
446 Ok(())
447 }
448 _ => Err(ErrorKind::PathTraversal(format!(
449 "cannot set '{}': parent is not a group",
450 path
451 ))
452 .into()),
453 },
454 PathSegment::Index(index) => match current {
455 Value::Array(arr) | Value::List(arr) => {
456 if *index < arr.len() {
457 arr[*index] = value.into();
458 Ok(())
459 } else {
460 Err(ErrorKind::PathTraversal(format!(
461 "index {} out of bounds (length {}) in '{}'",
462 index,
463 arr.len(),
464 path
465 ))
466 .into())
467 }
468 }
469 _ => Err(ErrorKind::PathTraversal(format!(
470 "cannot set '{}': parent is not an array or list",
471 path
472 ))
473 .into()),
474 },
475 }
476 }
477
478 pub fn remove(&mut self, path: &str) -> Option<Value> {
496 let segments = parse_path(path)?;
497 if segments.is_empty() {
498 return None;
499 }
500
501 let mut current = self;
502
503 for segment in &segments[..segments.len() - 1] {
505 match segment {
506 PathSegment::Key(key) => match current {
507 Value::Group(map) => current = map.get_mut(*key)?,
508 _ => return None,
509 },
510 PathSegment::Index(index) => match current {
511 Value::Array(arr) | Value::List(arr) => current = arr.get_mut(*index)?,
512 _ => return None,
513 },
514 }
515 }
516
517 match segments.last().unwrap() {
519 PathSegment::Key(key) => match current {
520 Value::Group(map) => map.shift_remove(*key),
521 _ => None,
522 },
523 PathSegment::Index(index) => match current {
524 Value::Array(arr) | Value::List(arr) => {
525 if *index < arr.len() {
526 Some(arr.remove(*index))
527 } else {
528 None
529 }
530 }
531 _ => None,
532 },
533 }
534 }
535
536 #[allow(clippy::should_implement_trait)] pub fn from_str(s: &str) -> Result<Value> {
549 crate::from_str(s)
550 }
551
552}
553
554impl std::str::FromStr for Value {
555 type Err = Error;
556
557 fn from_str(s: &str) -> Result<Value> {
558 crate::from_str(s)
559 }
560}
561
562impl From<bool> for Value {
564 fn from(v: bool) -> Value {
565 Value::Bool(v)
566 }
567}
568
569impl From<i8> for Value {
570 fn from(v: i8) -> Value {
571 Value::Integer(i32::from(v))
572 }
573}
574
575impl From<i16> for Value {
576 fn from(v: i16) -> Value {
577 Value::Integer(i32::from(v))
578 }
579}
580
581impl From<i32> for Value {
582 fn from(v: i32) -> Value {
583 Value::Integer(v)
584 }
585}
586
587impl From<i64> for Value {
588 fn from(v: i64) -> Value {
589 Value::Integer64(v)
590 }
591}
592
593impl From<u8> for Value {
594 fn from(v: u8) -> Value {
595 Value::Integer(i32::from(v))
596 }
597}
598
599impl From<u16> for Value {
600 fn from(v: u16) -> Value {
601 Value::Integer(i32::from(v))
602 }
603}
604
605impl From<u32> for Value {
606 fn from(v: u32) -> Value {
607 if v > i32::MAX as u32 {
609 Value::Integer64(i64::from(v))
610 } else {
611 Value::Integer(v as i32)
612 }
613 }
614}
615
616impl From<f32> for Value {
617 fn from(v: f32) -> Value {
618 Value::Float(f64::from(v))
619 }
620}
621
622impl From<f64> for Value {
623 fn from(v: f64) -> Value {
624 Value::Float(v)
625 }
626}
627
628impl From<&str> for Value {
629 fn from(v: &str) -> Value {
630 Value::String(v.to_string())
631 }
632}
633
634impl From<String> for Value {
635 fn from(v: String) -> Value {
636 Value::String(v)
637 }
638}
639
640impl From<Map> for Value {
641 fn from(v: Map) -> Value {
642 Value::Group(v)
643 }
644}
645
646impl Index<&str> for Value {
654 type Output = Value;
655
656 fn index(&self, key: &str) -> &Self::Output {
657 self.lookup(key)
658 .unwrap_or_else(|| panic!("path '{}' not found", key))
659 }
660}
661
662impl Index<usize> for Value {
669 type Output = Value;
670
671 fn index(&self, index: usize) -> &Self::Output {
672 self.get_index(index)
673 .unwrap_or_else(|| panic!("index {} out of bounds", index))
674 }
675}
676
677impl PartialEq<bool> for Value {
679 fn eq(&self, other: &bool) -> bool {
680 self.as_bool() == Some(*other)
681 }
682}
683
684impl PartialEq<i32> for Value {
685 fn eq(&self, other: &i32) -> bool {
686 self.as_i32() == Some(*other)
687 }
688}
689
690impl PartialEq<i64> for Value {
691 fn eq(&self, other: &i64) -> bool {
692 self.as_i64() == Some(*other)
693 }
694}
695
696impl PartialEq<f64> for Value {
697 fn eq(&self, other: &f64) -> bool {
698 self.as_f64() == Some(*other)
699 }
700}
701
702impl PartialEq<str> for Value {
703 fn eq(&self, other: &str) -> bool {
704 self.as_str() == Some(other)
705 }
706}
707
708impl PartialEq<&str> for Value {
709 fn eq(&self, other: &&str) -> bool {
710 self.as_str() == Some(*other)
711 }
712}
713
714impl PartialEq<String> for Value {
715 fn eq(&self, other: &String) -> bool {
716 self.as_str() == Some(other.as_str())
717 }
718}
719
720impl PartialEq<Value> for bool {
722 fn eq(&self, other: &Value) -> bool {
723 other == self
724 }
725}
726
727impl PartialEq<Value> for i32 {
728 fn eq(&self, other: &Value) -> bool {
729 other == self
730 }
731}
732
733impl PartialEq<Value> for i64 {
734 fn eq(&self, other: &Value) -> bool {
735 other == self
736 }
737}
738
739impl PartialEq<Value> for f64 {
740 fn eq(&self, other: &Value) -> bool {
741 other == self
742 }
743}
744
745impl PartialEq<Value> for str {
746 fn eq(&self, other: &Value) -> bool {
747 other == self
748 }
749}
750
751impl PartialEq<Value> for &str {
752 fn eq(&self, other: &Value) -> bool {
753 other == *self
754 }
755}
756
757impl PartialEq<Value> for String {
758 fn eq(&self, other: &Value) -> bool {
759 other == self
760 }
761}
762
763impl fmt::Display for Value {
766 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
767 match self {
768 Value::Bool(b) => write!(f, "{}", b),
769 Value::Integer(i) => write!(f, "{}", i),
770 Value::Integer64(i) => write!(f, "{}L", i),
771 Value::Float(fl) => {
772 let mut s = String::new();
773 match write_f64(&mut s, *fl, &crate::WriteOptions::default()) {
776 Ok(()) => f.write_str(&s),
777 Err(_) => write!(f, "{}", fl),
778 }
779 }
780 Value::String(s) => {
781 let mut escaped = String::with_capacity(s.len() + 2);
782 escape_str_into(&mut escaped, s);
783 f.write_str(&escaped)
784 }
785 Value::Array(arr) => {
786 write!(f, "[")?;
787 for (i, v) in arr.iter().enumerate() {
788 if i > 0 {
789 write!(f, ", ")?;
790 }
791 write!(f, "{}", v)?;
792 }
793 write!(f, "]")
794 }
795 Value::List(arr) => {
796 write!(f, "(")?;
797 for (i, v) in arr.iter().enumerate() {
798 if i > 0 {
799 write!(f, ", ")?;
800 }
801 write!(f, "{}", v)?;
802 }
803 write!(f, ")")
804 }
805 Value::Group(map) => {
806 write!(f, "{{")?;
807 for (k, v) in map.iter() {
808 write!(f, " {} = {};", k, v)?;
809 }
810 write!(f, " }}")
811 }
812 }
813 }
814}
815
816impl Serialize for Value {
818 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
819 where
820 S: Serializer,
821 {
822 match self {
823 Value::Bool(b) => serializer.serialize_bool(*b),
824 Value::Integer(i) => serializer.serialize_i32(*i),
825 Value::Integer64(i) => serializer.serialize_i64(*i),
826 Value::Float(f) => serializer.serialize_f64(*f),
827 Value::String(s) => serializer.serialize_str(s),
828 Value::Array(arr) => {
829 let mut seq = serializer.serialize_seq(Some(arr.len()))?;
830 for element in arr {
831 seq.serialize_element(element)?;
832 }
833 seq.end()
834 }
835 Value::List(arr) => {
836 use serde::ser::SerializeTuple;
837 let mut tup = serializer.serialize_tuple(arr.len())?;
838 for element in arr {
839 tup.serialize_element(element)?;
840 }
841 tup.end()
842 }
843 Value::Group(map) => {
844 let mut map_ser = serializer.serialize_map(Some(map.len()))?;
845 for (k, v) in map {
846 map_ser.serialize_entry(k, v)?;
847 }
848 map_ser.end()
849 }
850 }
851 }
852}
853
854impl<'de> Deserialize<'de> for Value {
856 fn deserialize<D>(deserializer: D) -> std::result::Result<Value, D::Error>
857 where
858 D: Deserializer<'de>,
859 {
860 deserializer.deserialize_any(ValueVisitor)
861 }
862}
863
864pub(crate) fn scalar_family(v: &Value) -> Option<u8> {
868 match v {
869 Value::Bool(_) => Some(0),
870 Value::Integer(_) | Value::Integer64(_) => Some(1),
871 Value::Float(_) => Some(2),
872 Value::String(_) => Some(3),
873 _ => None,
874 }
875}
876
877pub(crate) fn is_homogeneous_scalar_seq(values: &[Value]) -> bool {
880 let mut family = None;
881 for v in values {
882 let Some(f) = scalar_family(v) else {
883 return false;
884 };
885 match family {
886 None => family = Some(f),
887 Some(prev) if prev != f => return false,
888 _ => {}
889 }
890 }
891 true
892}
893
894struct ValueVisitor;
895
896impl<'de> Visitor<'de> for ValueVisitor {
897 type Value = Value;
898
899 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
900 formatter.write_str("any valid libconfig value")
901 }
902
903 fn visit_bool<E>(self, value: bool) -> std::result::Result<Value, E>
904 where
905 E: de::Error,
906 {
907 Ok(Value::Bool(value))
908 }
909
910 fn visit_i8<E>(self, value: i8) -> std::result::Result<Value, E>
911 where
912 E: de::Error,
913 {
914 Ok(Value::Integer(value as i32))
915 }
916
917 fn visit_i16<E>(self, value: i16) -> std::result::Result<Value, E>
918 where
919 E: de::Error,
920 {
921 Ok(Value::Integer(value as i32))
922 }
923
924 fn visit_i32<E>(self, value: i32) -> std::result::Result<Value, E>
925 where
926 E: de::Error,
927 {
928 Ok(Value::Integer(value))
929 }
930
931 fn visit_i64<E>(self, value: i64) -> std::result::Result<Value, E>
932 where
933 E: de::Error,
934 {
935 Ok(Value::Integer64(value))
936 }
937
938 fn visit_u8<E>(self, value: u8) -> std::result::Result<Value, E>
939 where
940 E: de::Error,
941 {
942 Ok(Value::Integer(value as i32))
943 }
944
945 fn visit_u16<E>(self, value: u16) -> std::result::Result<Value, E>
946 where
947 E: de::Error,
948 {
949 Ok(Value::Integer(value as i32))
950 }
951
952 fn visit_u32<E>(self, value: u32) -> std::result::Result<Value, E>
953 where
954 E: de::Error,
955 {
956 if value <= i32::MAX as u32 {
957 Ok(Value::Integer(value as i32))
958 } else {
959 Ok(Value::Integer64(value as i64))
960 }
961 }
962
963 fn visit_u64<E>(self, value: u64) -> std::result::Result<Value, E>
964 where
965 E: de::Error,
966 {
967 if value <= i32::MAX as u64 {
968 Ok(Value::Integer(value as i32))
969 } else {
970 Ok(Value::Integer64(value as i64))
971 }
972 }
973
974 fn visit_f32<E>(self, value: f32) -> std::result::Result<Value, E>
975 where
976 E: de::Error,
977 {
978 Ok(Value::Float(value as f64))
979 }
980
981 fn visit_f64<E>(self, value: f64) -> std::result::Result<Value, E>
982 where
983 E: de::Error,
984 {
985 Ok(Value::Float(value))
986 }
987
988 fn visit_str<E>(self, value: &str) -> std::result::Result<Value, E>
989 where
990 E: de::Error,
991 {
992 Ok(Value::String(value.to_string()))
993 }
994
995 fn visit_borrowed_str<E>(self, value: &'de str) -> std::result::Result<Value, E>
996 where
997 E: de::Error,
998 {
999 Ok(Value::String(value.to_string()))
1000 }
1001
1002 fn visit_string<E>(self, value: String) -> std::result::Result<Value, E>
1003 where
1004 E: de::Error,
1005 {
1006 Ok(Value::String(value))
1007 }
1008
1009 fn visit_seq<A>(self, mut seq: A) -> std::result::Result<Value, A::Error>
1010 where
1011 A: SeqAccess<'de>,
1012 {
1013 let context = take_list_context();
1016 let mut values = Vec::new();
1017 while let Some(value) = seq.next_element()? {
1018 values.push(value);
1019 }
1020 match context {
1021 Some(true) => Ok(Value::List(values)),
1022 Some(false) => {
1023 if !is_homogeneous_scalar_seq(&values) {
1027 return Err(de::Error::custom(
1028 "array elements must all be scalar values of the same type",
1029 ));
1030 }
1031 Ok(Value::Array(values))
1032 }
1033 None => {
1036 if is_homogeneous_scalar_seq(&values) {
1037 Ok(Value::Array(values))
1038 } else {
1039 Ok(Value::List(values))
1040 }
1041 }
1042 }
1043 }
1044
1045 fn visit_map<A>(self, mut map: A) -> std::result::Result<Value, A::Error>
1046 where
1047 A: MapAccess<'de>,
1048 {
1049 let mut values = Map::new();
1050 while let Some((key, value)) = map.next_entry::<String, Value>()? {
1051 match values.entry(key) {
1055 indexmap::map::Entry::Occupied(entry) => {
1056 return Err(de::Error::custom(format!(
1057 "duplicate setting name '{}'",
1058 entry.key()
1059 )));
1060 }
1061 indexmap::map::Entry::Vacant(entry) => {
1062 entry.insert(value);
1063 }
1064 }
1065 }
1066 Ok(Value::Group(values))
1067 }
1068}
1069
1070pub fn to_value<T>(value: &T) -> Result<Value>
1096where
1097 T: ?Sized + Serialize,
1098{
1099 value.serialize(ValueSerializer)
1100}
1101
1102struct ValueSerializer;
1104
1105impl Serializer for ValueSerializer {
1106 type Ok = Value;
1107 type Error = Error;
1108
1109 type SerializeSeq = SerializeValueSeq;
1110 type SerializeTuple = SerializeValueList;
1111 type SerializeTupleStruct = SerializeValueList;
1112 type SerializeTupleVariant = SerializeValueTupleVariant;
1113 type SerializeMap = SerializeValueMap;
1114 type SerializeStruct = SerializeValueMap;
1115 type SerializeStructVariant = SerializeValueStructVariant;
1116
1117 fn serialize_bool(self, v: bool) -> Result<Value> {
1118 Ok(Value::Bool(v))
1119 }
1120
1121 fn serialize_i8(self, v: i8) -> Result<Value> {
1122 Ok(Value::Integer(i32::from(v)))
1123 }
1124
1125 fn serialize_i16(self, v: i16) -> Result<Value> {
1126 Ok(Value::Integer(i32::from(v)))
1127 }
1128
1129 fn serialize_i32(self, v: i32) -> Result<Value> {
1130 Ok(Value::Integer(v))
1131 }
1132
1133 fn serialize_i64(self, v: i64) -> Result<Value> {
1134 Ok(Value::Integer64(v))
1135 }
1136
1137 fn serialize_u8(self, v: u8) -> Result<Value> {
1138 Ok(Value::Integer(i32::from(v)))
1139 }
1140
1141 fn serialize_u16(self, v: u16) -> Result<Value> {
1142 Ok(Value::Integer(i32::from(v)))
1143 }
1144
1145 fn serialize_u32(self, v: u32) -> Result<Value> {
1146 Ok(Value::from(v))
1147 }
1148
1149 fn serialize_u64(self, v: u64) -> Result<Value> {
1150 i64::try_from(v)
1151 .map(Value::Integer64)
1152 .map_err(|_| ErrorKind::IntegerOutOfRange.into())
1153 }
1154
1155 fn serialize_f32(self, v: f32) -> Result<Value> {
1156 Ok(Value::Float(f64::from(v)))
1157 }
1158
1159 fn serialize_f64(self, v: f64) -> Result<Value> {
1160 Ok(Value::Float(v))
1161 }
1162
1163 fn serialize_char(self, v: char) -> Result<Value> {
1164 Ok(Value::String(v.to_string()))
1165 }
1166
1167 fn serialize_str(self, v: &str) -> Result<Value> {
1168 Ok(Value::String(v.to_string()))
1169 }
1170
1171 fn serialize_bytes(self, v: &[u8]) -> Result<Value> {
1172 Ok(Value::Array(
1173 v.iter().map(|b| Value::Integer(i32::from(*b))).collect(),
1174 ))
1175 }
1176
1177 fn serialize_none(self) -> Result<Value> {
1178 Err(ErrorKind::TypeNotSupported("Option::None".to_string()).into())
1179 }
1180
1181 fn serialize_some<T: ?Sized + Serialize>(self, value: &T) -> Result<Value> {
1182 value.serialize(self)
1183 }
1184
1185 fn serialize_unit(self) -> Result<Value> {
1186 Err(ErrorKind::UnitNotSupported.into())
1187 }
1188
1189 fn serialize_unit_struct(self, _name: &'static str) -> Result<Value> {
1190 self.serialize_unit()
1191 }
1192
1193 fn serialize_unit_variant(
1194 self,
1195 _name: &'static str,
1196 _variant_index: u32,
1197 variant: &'static str,
1198 ) -> Result<Value> {
1199 Ok(Value::String(variant.to_string()))
1200 }
1201
1202 fn serialize_newtype_struct<T: ?Sized + Serialize>(
1203 self,
1204 _name: &'static str,
1205 value: &T,
1206 ) -> Result<Value> {
1207 value.serialize(self)
1208 }
1209
1210 fn serialize_newtype_variant<T: ?Sized + Serialize>(
1211 self,
1212 _name: &'static str,
1213 _variant_index: u32,
1214 variant: &'static str,
1215 value: &T,
1216 ) -> Result<Value> {
1217 validate_variant_name(variant)?;
1218 let mut map = Map::new();
1219 map.insert(variant.to_string(), value.serialize(ValueSerializer)?);
1220 Ok(Value::Group(map))
1221 }
1222
1223 fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq> {
1224 Ok(SerializeValueSeq {
1225 items: Vec::with_capacity(len.unwrap_or(0)),
1226 })
1227 }
1228
1229 fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple> {
1230 Ok(SerializeValueList {
1231 items: Vec::with_capacity(len),
1232 })
1233 }
1234
1235 fn serialize_tuple_struct(
1236 self,
1237 _name: &'static str,
1238 len: usize,
1239 ) -> Result<Self::SerializeTupleStruct> {
1240 self.serialize_tuple(len)
1241 }
1242
1243 fn serialize_tuple_variant(
1244 self,
1245 _name: &'static str,
1246 _variant_index: u32,
1247 variant: &'static str,
1248 len: usize,
1249 ) -> Result<Self::SerializeTupleVariant> {
1250 validate_variant_name(variant)?;
1251 Ok(SerializeValueTupleVariant {
1252 variant,
1253 items: Vec::with_capacity(len),
1254 })
1255 }
1256
1257 fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap> {
1258 Ok(SerializeValueMap {
1259 map: Map::new(),
1260 pending_key: None,
1261 })
1262 }
1263
1264 fn serialize_struct(self, _name: &'static str, _len: usize) -> Result<Self::SerializeStruct> {
1265 Ok(SerializeValueMap {
1266 map: Map::new(),
1267 pending_key: None,
1268 })
1269 }
1270
1271 fn serialize_struct_variant(
1272 self,
1273 _name: &'static str,
1274 _variant_index: u32,
1275 variant: &'static str,
1276 _len: usize,
1277 ) -> Result<Self::SerializeStructVariant> {
1278 validate_variant_name(variant)?;
1279 Ok(SerializeValueStructVariant {
1280 variant,
1281 map: Map::new(),
1282 })
1283 }
1284}
1285
1286fn validate_variant_name(name: &str) -> Result<()> {
1287 if crate::ser::is_valid_name(name) {
1288 Ok(())
1289 } else {
1290 Err(ErrorKind::InvalidSettingName(name.to_string()).into())
1291 }
1292}
1293
1294struct SerializeValueSeq {
1295 items: Vec<Value>,
1296}
1297
1298impl serde::ser::SerializeSeq for SerializeValueSeq {
1299 type Ok = Value;
1300 type Error = Error;
1301
1302 fn serialize_element<T: ?Sized + Serialize>(&mut self, value: &T) -> Result<()> {
1303 self.items.push(value.serialize(ValueSerializer)?);
1304 Ok(())
1305 }
1306
1307 fn end(self) -> Result<Value> {
1308 if is_homogeneous_scalar_seq(&self.items) {
1311 Ok(Value::Array(self.items))
1312 } else {
1313 Ok(Value::List(self.items))
1314 }
1315 }
1316}
1317
1318struct SerializeValueList {
1319 items: Vec<Value>,
1320}
1321
1322impl serde::ser::SerializeTuple for SerializeValueList {
1323 type Ok = Value;
1324 type Error = Error;
1325
1326 fn serialize_element<T: ?Sized + Serialize>(&mut self, value: &T) -> Result<()> {
1327 self.items.push(value.serialize(ValueSerializer)?);
1328 Ok(())
1329 }
1330
1331 fn end(self) -> Result<Value> {
1332 Ok(Value::List(self.items))
1333 }
1334}
1335
1336impl serde::ser::SerializeTupleStruct for SerializeValueList {
1337 type Ok = Value;
1338 type Error = Error;
1339
1340 fn serialize_field<T: ?Sized + Serialize>(&mut self, value: &T) -> Result<()> {
1341 self.items.push(value.serialize(ValueSerializer)?);
1342 Ok(())
1343 }
1344
1345 fn end(self) -> Result<Value> {
1346 Ok(Value::List(self.items))
1347 }
1348}
1349
1350struct SerializeValueTupleVariant {
1351 variant: &'static str,
1352 items: Vec<Value>,
1353}
1354
1355impl serde::ser::SerializeTupleVariant for SerializeValueTupleVariant {
1356 type Ok = Value;
1357 type Error = Error;
1358
1359 fn serialize_field<T: ?Sized + Serialize>(&mut self, value: &T) -> Result<()> {
1360 self.items.push(value.serialize(ValueSerializer)?);
1361 Ok(())
1362 }
1363
1364 fn end(self) -> Result<Value> {
1365 let mut map = Map::new();
1366 map.insert(self.variant.to_string(), Value::List(self.items));
1367 Ok(Value::Group(map))
1368 }
1369}
1370
1371struct SerializeValueMap {
1372 map: Map,
1373 pending_key: Option<String>,
1374}
1375
1376impl serde::ser::SerializeMap for SerializeValueMap {
1377 type Ok = Value;
1378 type Error = Error;
1379
1380 fn serialize_key<T: ?Sized + Serialize>(&mut self, key: &T) -> Result<()> {
1381 let mut key_capture = crate::ser::KeyCapture { key: String::new() };
1382 key.serialize(&mut key_capture)?;
1383 self.pending_key = Some(key_capture.key);
1384 Ok(())
1385 }
1386
1387 fn serialize_value<T: ?Sized + Serialize>(&mut self, value: &T) -> Result<()> {
1388 let key = self.pending_key.take().ok_or_else(|| {
1389 Error::from(ErrorKind::Message(
1390 "serialize_value called without serialize_key".to_string(),
1391 ))
1392 })?;
1393 self.map.insert(key, value.serialize(ValueSerializer)?);
1394 Ok(())
1395 }
1396
1397 fn end(self) -> Result<Value> {
1398 Ok(Value::Group(self.map))
1399 }
1400}
1401
1402impl serde::ser::SerializeStruct for SerializeValueMap {
1403 type Ok = Value;
1404 type Error = Error;
1405
1406 fn serialize_field<T: ?Sized + Serialize>(
1407 &mut self,
1408 key: &'static str,
1409 value: &T,
1410 ) -> Result<()> {
1411 validate_variant_name(key)?;
1412 self.map.insert(key.to_string(), value.serialize(ValueSerializer)?);
1413 Ok(())
1414 }
1415
1416 fn end(self) -> Result<Value> {
1417 Ok(Value::Group(self.map))
1418 }
1419}
1420
1421struct SerializeValueStructVariant {
1422 variant: &'static str,
1423 map: Map,
1424}
1425
1426impl serde::ser::SerializeStructVariant for SerializeValueStructVariant {
1427 type Ok = Value;
1428 type Error = Error;
1429
1430 fn serialize_field<T: ?Sized + Serialize>(
1431 &mut self,
1432 key: &'static str,
1433 value: &T,
1434 ) -> Result<()> {
1435 validate_variant_name(key)?;
1436 self.map.insert(key.to_string(), value.serialize(ValueSerializer)?);
1437 Ok(())
1438 }
1439
1440 fn end(self) -> Result<Value> {
1441 let mut inner = Map::new();
1442 inner.insert(self.variant.to_string(), Value::Group(self.map));
1443 Ok(Value::Group(inner))
1444 }
1445}
1446
1447pub fn from_value<T>(value: Value) -> Result<T>
1459where
1460 T: de::DeserializeOwned,
1461{
1462 let result = T::deserialize(value);
1463 crate::de::clear_list_context();
1464 result
1465}
1466
1467impl<'de> Deserializer<'de> for Value {
1469 type Error = Error;
1470
1471 fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
1472 where
1473 V: Visitor<'de>,
1474 {
1475 match self {
1476 Value::Bool(b) => visitor.visit_bool(b),
1477 Value::Integer(i) => visitor.visit_i32(i),
1478 Value::Integer64(i) => visitor.visit_i64(i),
1479 Value::Float(f) => visitor.visit_f64(f),
1480 Value::String(s) => visitor.visit_string(s),
1481 Value::Array(arr) => {
1482 set_list_context(false);
1486 visitor.visit_seq(SeqDeserializer::new(arr.into_iter()))
1487 }
1488 Value::List(arr) => {
1489 set_list_context(true);
1490 visitor.visit_seq(SeqDeserializer::new(arr.into_iter()))
1491 }
1492 Value::Group(map) => visitor.visit_map(MapDeserializer::new(map.into_iter())),
1493 }
1494 }
1495
1496 fn deserialize_option<V>(self, visitor: V) -> Result<V::Value>
1497 where
1498 V: Visitor<'de>,
1499 {
1500 visitor.visit_some(self)
1501 }
1502
1503 fn deserialize_enum<V>(
1504 self,
1505 _name: &'static str,
1506 _variants: &'static [&'static str],
1507 visitor: V,
1508 ) -> Result<V::Value>
1509 where
1510 V: Visitor<'de>,
1511 {
1512 match self {
1513 Value::String(s) => visitor.visit_enum(s.into_deserializer()),
1515 Value::Group(map) => {
1517 if map.len() != 1 {
1518 return Err(ErrorKind::Message(
1519 "expected a group with a single setting for an enum variant".to_string(),
1520 ).into());
1521 }
1522 let (variant, value) = map.into_iter().next().unwrap();
1523 visitor.visit_enum(ValueEnumAccess { variant, value })
1524 }
1525 _ => Err(ErrorKind::Message(
1526 "expected a string or group for an enum".to_string(),
1527 ).into()),
1528 }
1529 }
1530
1531 serde::forward_to_deserialize_any! {
1532 bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string
1533 bytes byte_buf unit unit_struct newtype_struct seq tuple
1534 tuple_struct map struct identifier ignored_any
1535 }
1536}
1537
1538struct ValueEnumAccess {
1539 variant: String,
1540 value: Value,
1541}
1542
1543impl<'de> de::EnumAccess<'de> for ValueEnumAccess {
1544 type Error = Error;
1545 type Variant = ValueVariantAccess;
1546
1547 fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant)>
1548 where
1549 V: de::DeserializeSeed<'de>,
1550 {
1551 let variant_de: de::value::StringDeserializer<Error> = self.variant.into_deserializer();
1552 let variant = seed.deserialize(variant_de)?;
1553 Ok((variant, ValueVariantAccess { value: self.value }))
1554 }
1555}
1556
1557struct ValueVariantAccess {
1558 value: Value,
1559}
1560
1561impl<'de> de::VariantAccess<'de> for ValueVariantAccess {
1562 type Error = Error;
1563
1564 fn unit_variant(self) -> Result<()> {
1565 Err(ErrorKind::Message(
1566 "unit enum variants are represented as strings, not groups".to_string(),
1567 ).into())
1568 }
1569
1570 fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value>
1571 where
1572 T: de::DeserializeSeed<'de>,
1573 {
1574 seed.deserialize(self.value)
1575 }
1576
1577 fn tuple_variant<V>(self, _len: usize, visitor: V) -> Result<V::Value>
1578 where
1579 V: Visitor<'de>,
1580 {
1581 match self.value {
1582 Value::Array(arr) | Value::List(arr) => {
1583 visitor.visit_seq(SeqDeserializer::new(arr.into_iter()))
1584 }
1585 _ => Err(ErrorKind::Message(
1586 "expected a list for a tuple enum variant".to_string(),
1587 ).into()),
1588 }
1589 }
1590
1591 fn struct_variant<V>(self, _fields: &'static [&'static str], visitor: V) -> Result<V::Value>
1592 where
1593 V: Visitor<'de>,
1594 {
1595 match self.value {
1596 Value::Group(map) => visitor.visit_map(MapDeserializer::new(map.into_iter())),
1597 _ => Err(ErrorKind::Message(
1598 "expected a group for a struct enum variant".to_string(),
1599 ).into()),
1600 }
1601 }
1602}
1603
1604struct SeqDeserializer {
1605 iter: std::vec::IntoIter<Value>,
1606}
1607
1608impl SeqDeserializer {
1609 fn new(iter: std::vec::IntoIter<Value>) -> Self {
1610 SeqDeserializer { iter }
1611 }
1612}
1613
1614impl<'de> SeqAccess<'de> for SeqDeserializer {
1615 type Error = Error;
1616
1617 fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>>
1618 where
1619 T: de::DeserializeSeed<'de>,
1620 {
1621 match self.iter.next() {
1622 Some(value) => seed.deserialize(value).map(Some),
1623 None => Ok(None),
1624 }
1625 }
1626}
1627
1628struct MapDeserializer {
1629 iter: indexmap::map::IntoIter<String, Value>,
1630 value: Option<Value>,
1631}
1632
1633impl MapDeserializer {
1634 fn new(iter: indexmap::map::IntoIter<String, Value>) -> Self {
1635 MapDeserializer { iter, value: None }
1636 }
1637}
1638
1639impl<'de> MapAccess<'de> for MapDeserializer {
1640 type Error = Error;
1641
1642 fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>
1643 where
1644 K: de::DeserializeSeed<'de>,
1645 {
1646 match self.iter.next() {
1647 Some((key, value)) => {
1648 self.value = Some(value);
1649 seed.deserialize(Value::String(key)).map(Some)
1650 }
1651 None => Ok(None),
1652 }
1653 }
1654
1655 fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value>
1656 where
1657 V: de::DeserializeSeed<'de>,
1658 {
1659 match self.value.take() {
1660 Some(value) => seed.deserialize(value),
1661 None => Err(ErrorKind::Message("value is missing".to_string()).into()),
1662 }
1663 }
1664}
1665
1666const MAX_INCLUDE_DEPTH: usize = 10;
1669
1670type IncludeResolver<'a> = dyn Fn(&str) -> Result<Vec<std::path::PathBuf>> + 'a;
1679
1680fn default_include_resolver(
1684 include_dir: Option<&Path>,
1685) -> impl Fn(&str) -> Result<Vec<std::path::PathBuf>> + '_ {
1686 move |path: &str| {
1687 let mut resolved = std::path::PathBuf::from(path);
1688 if resolved.is_relative() {
1689 if let Some(dir) = include_dir {
1690 resolved = dir.join(resolved);
1691 }
1692 }
1693 Ok(vec![resolved])
1694 }
1695}
1696
1697fn resolve_includes(input: &str, resolver: &IncludeResolver, depth: usize) -> Result<String> {
1701 if depth > MAX_INCLUDE_DEPTH {
1702 return Err(ErrorKind::Include(format!(
1703 "include files nested too deeply (maximum {} levels)",
1704 MAX_INCLUDE_DEPTH
1705 ))
1706 .into());
1707 }
1708
1709 let mut out = String::with_capacity(input.len());
1710 let mut in_block_comment = false;
1711
1712 for line in input.lines() {
1713 let trimmed = line.trim_start();
1714 if !in_block_comment && trimmed.starts_with("@include") {
1715 let path_str = parse_include_path(&trimmed["@include".len()..])?;
1716 for path in resolver(&path_str)? {
1717 let contents = std::fs::read_to_string(&path).map_err(|e| {
1718 ErrorKind::Include(format!(
1719 "failed to read include file '{}': {}",
1720 path.display(),
1721 e
1722 ))
1723 })?;
1724 out.push_str(&resolve_includes(&contents, resolver, depth + 1)?);
1725 out.push('\n');
1726 }
1727 } else {
1728 update_block_comment_state(line, &mut in_block_comment);
1729 out.push_str(line);
1730 out.push('\n');
1731 }
1732 }
1733
1734 Ok(out)
1735}
1736
1737fn parse_include_path(rest: &str) -> Result<String> {
1740 let rest = rest.trim_start();
1741 let mut chars = rest.chars();
1742 if chars.next() != Some('"') {
1743 return Err(ErrorKind::Include(
1744 "expected a quoted path after @include".to_string(),
1745 ).into());
1746 }
1747
1748 let mut path = String::new();
1749 let mut escaped = false;
1750 let mut closed = false;
1751 for ch in chars.by_ref() {
1752 if escaped {
1753 match ch {
1754 '\\' => path.push('\\'),
1755 '"' => path.push('"'),
1756 _ => {
1757 return Err(ErrorKind::Include(format!(
1758 "invalid escape '\\{}' in @include path",
1759 ch
1760 )).into());
1761 }
1762 }
1763 escaped = false;
1764 } else if ch == '\\' {
1765 escaped = true;
1766 } else if ch == '"' {
1767 closed = true;
1768 break;
1769 } else {
1770 path.push(ch);
1771 }
1772 }
1773 if !closed {
1774 return Err(ErrorKind::Include(
1775 "unterminated path in @include directive".to_string(),
1776 ).into());
1777 }
1778
1779 let remainder = chars.as_str().trim_start();
1781 if !(remainder.is_empty() || remainder.starts_with('#') || remainder.starts_with("//")) {
1782 return Err(ErrorKind::Include(
1783 "unexpected content after @include directive".to_string(),
1784 ).into());
1785 }
1786
1787 Ok(path)
1788}
1789
1790fn update_block_comment_state(line: &str, in_block_comment: &mut bool) {
1793 let bytes = line.as_bytes();
1794 let mut i = 0;
1795 let mut in_string = false;
1796 while i < bytes.len() {
1797 if *in_block_comment {
1798 if bytes[i] == b'*' && bytes.get(i + 1) == Some(&b'/') {
1799 *in_block_comment = false;
1800 i += 2;
1801 } else {
1802 i += 1;
1803 }
1804 } else if in_string {
1805 match bytes[i] {
1806 b'\\' => i += 2,
1807 b'"' => {
1808 in_string = false;
1809 i += 1;
1810 }
1811 _ => i += 1,
1812 }
1813 } else {
1814 match bytes[i] {
1815 b'"' => {
1816 in_string = true;
1817 i += 1;
1818 }
1819 b'#' => break,
1820 b'/' if bytes.get(i + 1) == Some(&b'/') => break,
1821 b'/' if bytes.get(i + 1) == Some(&b'*') => {
1822 *in_block_comment = true;
1823 i += 2;
1824 }
1825 _ => i += 1,
1826 }
1827 }
1828 }
1829}
1830
1831#[derive(Debug, Clone, PartialEq)]
1859pub struct Config {
1860 value: Value,
1863}
1864
1865impl Config {
1866 pub fn new() -> Self {
1868 Config {
1869 value: Value::Group(Map::new()),
1870 }
1871 }
1872
1873 pub fn into_value(self) -> Value {
1875 self.value
1876 }
1877
1878 #[allow(clippy::should_implement_trait)] pub fn from_str(s: &str) -> Result<Config> {
1896 Config::parse(s, &default_include_resolver(None))
1897 }
1898
1899 pub fn from_str_with_include_dir<P: AsRef<Path>>(s: &str, include_dir: P) -> Result<Config> {
1903 Config::parse(s, &default_include_resolver(Some(include_dir.as_ref())))
1904 }
1905
1906 pub fn from_str_with_include_fn<F>(s: &str, resolver: F) -> Result<Config>
1935 where
1936 F: Fn(&str) -> Result<Vec<std::path::PathBuf>>,
1937 {
1938 Config::parse(s, &resolver)
1939 }
1940
1941 fn parse(s: &str, resolver: &IncludeResolver) -> Result<Config> {
1942 let processed;
1943 let text: &str = if s.contains("@include") {
1944 processed = resolve_includes(s, resolver, 0)?;
1945 &processed
1946 } else {
1947 s
1948 };
1949 let value: Value = crate::from_str(text)?;
1950 if !value.is_group() {
1954 return Err(ErrorKind::ExpectedGroup.into());
1955 }
1956 Ok(Config { value })
1957 }
1958
1959 pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Config> {
1976 let contents = std::fs::read_to_string(path)
1977 .map_err(|e| ErrorKind::Message(format!("failed to read file: {}", e)))?;
1978 Config::from_str(&contents)
1979 }
1980
1981 pub fn from_file_with_include_dir<P: AsRef<Path>, Q: AsRef<Path>>(
1984 path: P,
1985 include_dir: Q,
1986 ) -> Result<Config> {
1987 let contents = std::fs::read_to_string(path)
1988 .map_err(|e| ErrorKind::Message(format!("failed to read file: {}", e)))?;
1989 Config::from_str_with_include_dir(&contents, include_dir)
1990 }
1991
1992 pub fn from_file_with_include_fn<P: AsRef<Path>, F>(path: P, resolver: F) -> Result<Config>
1995 where
1996 F: Fn(&str) -> Result<Vec<std::path::PathBuf>>,
1997 {
1998 let contents = std::fs::read_to_string(path)
1999 .map_err(|e| ErrorKind::Message(format!("failed to read file: {}", e)))?;
2000 Config::parse(&contents, &resolver)
2001 }
2002
2003 pub fn to_string(&self) -> Result<String> {
2012 self.to_string_with_options(&crate::WriteOptions::default())
2013 }
2014
2015 pub fn to_string_with_options(&self, options: &crate::WriteOptions) -> Result<String> {
2018 if !self.value.is_group() {
2019 return Err(ErrorKind::ExpectedGroup.into());
2020 }
2021 crate::ser::to_string_with_options(&self.value, options)
2022 }
2023
2024 pub fn to_file<P: AsRef<Path>>(&self, path: P) -> Result<()> {
2032 self.to_file_with_options(path, &crate::WriteOptions::default())
2033 }
2034
2035 pub fn to_file_with_options<P: AsRef<Path>>(
2038 &self,
2039 path: P,
2040 options: &crate::WriteOptions,
2041 ) -> Result<()> {
2042 let mut contents = self.to_string_with_options(options)?;
2043 if !contents.is_empty() {
2044 contents.push('\n');
2045 }
2046 std::fs::write(path, contents).map_err(|e| ErrorKind::Io(e.to_string()))?;
2047 Ok(())
2048 }
2049}
2050
2051impl Default for Config {
2052 fn default() -> Self {
2053 Config::new()
2054 }
2055}
2056
2057impl std::str::FromStr for Config {
2058 type Err = Error;
2059
2060 fn from_str(s: &str) -> Result<Config> {
2061 Config::from_str(s)
2062 }
2063}
2064
2065impl TryFrom<Value> for Config {
2066 type Error = Error;
2067
2068 fn try_from(value: Value) -> Result<Config> {
2075 if value.is_group() {
2076 Ok(Config { value })
2077 } else {
2078 Err(ErrorKind::ExpectedGroup.into())
2079 }
2080 }
2081}
2082
2083impl<'de> Deserialize<'de> for Config {
2084 fn deserialize<D>(deserializer: D) -> std::result::Result<Config, D::Error>
2085 where
2086 D: Deserializer<'de>,
2087 {
2088 let value = Value::deserialize(deserializer)?;
2089 if value.is_group() {
2090 Ok(Config { value })
2091 } else {
2092 Err(de::Error::custom(
2093 "configuration root must be a group of settings",
2094 ))
2095 }
2096 }
2097}
2098
2099impl std::ops::Deref for Config {
2100 type Target = Value;
2101
2102 fn deref(&self) -> &Value {
2103 &self.value
2104 }
2105}
2106
2107impl std::ops::DerefMut for Config {
2108 fn deref_mut(&mut self) -> &mut Value {
2109 &mut self.value
2110 }
2111}
2112
2113impl fmt::Display for Config {
2114 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2115 match self.to_string() {
2116 Ok(s) => write!(f, "{}", s),
2117 Err(e) => write!(f, "<error: {}>", e),
2118 }
2119 }
2120}
2121
2122impl Serialize for Config {
2123 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
2124 where
2125 S: Serializer,
2126 {
2127 self.value.serialize(serializer)
2128 }
2129}
2130
2131#[cfg(test)]
2132mod tests {
2133 use super::*;
2134 use crate::from_str;
2135
2136 #[test]
2137 fn test_value_types() {
2138 let v = Value::Bool(true);
2139 assert!(v.is_bool());
2140 assert_eq!(v.as_bool(), Some(true));
2141
2142 let v = Value::Integer(42);
2143 assert!(v.is_i32());
2144 assert_eq!(v.as_i32(), Some(42));
2145
2146 let v = Value::Float(2.25);
2147 assert!(v.is_float());
2148 assert_eq!(v.as_f64(), Some(2.25));
2149
2150 let v = Value::String("hello".to_string());
2151 assert!(v.is_string());
2152 assert_eq!(v.as_str(), Some("hello"));
2153 }
2154
2155 #[test]
2156 fn test_value_indexing() {
2157 let config = r#"
2158 name = "Test";
2159 count = 42;
2160 items = [1, 2, 3];
2161 "#;
2162
2163 let v: Value = from_str(config).unwrap();
2164 assert_eq!(v["name"], "Test");
2165 assert_eq!(v["count"], 42);
2166 assert_eq!(v["items"][0], 1);
2167 assert_eq!(v["items"][1], 2);
2168 }
2169
2170 #[test]
2171 fn test_value_lookup() {
2172 let config = r#"
2173 application = {
2174 window = {
2175 title = "My App";
2176 size = { w = 640; h = 480; };
2177 };
2178 };
2179 "#;
2180
2181 let v: Value = from_str(config).unwrap();
2182 assert_eq!(
2183 v.lookup("application.window.title")
2184 .and_then(|v| v.as_str()),
2185 Some("My App")
2186 );
2187 assert_eq!(
2188 v.lookup("application.window.size")
2189 .and_then(|v| v.get("w"))
2190 .and_then(|v| v.as_i32()),
2191 Some(640)
2192 );
2193 }
2194
2195 #[test]
2196 fn test_value_lookup_with_array_index() {
2197 let config = r#"
2198 name = "Test";
2199 items = [10, 20, 30];
2200 nested = {
2201 ports = [80, 443];
2202 };
2203 "#;
2204
2205 let v: Value = from_str(config).unwrap();
2206
2207 assert_eq!(v.lookup("items.0").and_then(|v| v.as_i32()), Some(10));
2209 assert_eq!(v.lookup("items.1").and_then(|v| v.as_i32()), Some(20));
2210 assert_eq!(v.lookup("items.2").and_then(|v| v.as_i32()), Some(30));
2211
2212 assert_eq!(
2214 v.lookup("nested.ports.0").and_then(|v| v.as_i32()),
2215 Some(80)
2216 );
2217 assert_eq!(
2218 v.lookup("nested.ports.1").and_then(|v| v.as_i32()),
2219 Some(443)
2220 );
2221
2222 assert!(v.lookup("items.5").is_none());
2224
2225 assert!(v.lookup("name.0").is_none());
2227
2228 assert_eq!(v["items.0"], 10);
2230 assert_eq!(v["nested.ports.1"], 443);
2231 }
2232
2233 #[test]
2234 fn test_value_comparison() {
2235 let v = Value::Bool(true);
2236 assert!(v == true);
2237
2238 let v = Value::Integer(42);
2239 assert!(v == 42);
2240
2241 let v = Value::String("hello".to_string());
2242 assert!(v == "hello");
2243 }
2244
2245 #[test]
2246 fn test_value_round_trip() {
2247 let config = r#"
2248 name = "Test";
2249 version = 1;
2250 enabled = true;
2251 ratio = 2.25;
2252 items = [1, 2, 3];
2253 "#;
2254
2255 let v: Value = from_str(config).unwrap();
2256 let serialized = crate::to_string(&v).unwrap();
2257 let v2: Value = from_str(&serialized).unwrap();
2258
2259 assert_eq!(v["name"], v2["name"]);
2260 assert_eq!(v["version"], v2["version"]);
2261 assert_eq!(v["enabled"], v2["enabled"]);
2262 }
2263
2264 #[test]
2267 fn test_parse_path_dotted_keys() {
2268 let segs = parse_path("a.b.c").unwrap();
2269 assert_eq!(
2270 segs,
2271 vec![
2272 PathSegment::Key("a"),
2273 PathSegment::Key("b"),
2274 PathSegment::Key("c"),
2275 ]
2276 );
2277 }
2278
2279 #[test]
2280 fn test_parse_path_bracket_index() {
2281 let segs = parse_path("items.[0].title").unwrap();
2282 assert_eq!(
2283 segs,
2284 vec![
2285 PathSegment::Key("items"),
2286 PathSegment::Index(0),
2287 PathSegment::Key("title"),
2288 ]
2289 );
2290 }
2291
2292 #[test]
2293 fn test_parse_path_bare_numeric() {
2294 let segs = parse_path("items.0").unwrap();
2295 assert_eq!(segs, vec![PathSegment::Key("items"), PathSegment::Index(0)]);
2296 }
2297
2298 #[test]
2299 fn test_parse_path_single_segment() {
2300 assert_eq!(
2301 parse_path("version").unwrap(),
2302 vec![PathSegment::Key("version")]
2303 );
2304 }
2305
2306 #[test]
2307 fn test_parse_path_invalid() {
2308 assert!(parse_path("").is_none());
2309 assert!(parse_path("a..b").is_none());
2310 assert!(parse_path(".a").is_none());
2311 assert!(parse_path("a.").is_none());
2312 assert!(parse_path("items.[abc]").is_none());
2313 assert!(parse_path("items.[-1]").is_none());
2314 assert!(parse_path("items.[]").is_none());
2315 }
2316
2317 #[test]
2320 fn test_lookup_bracket_notation() {
2321 let config = r#"
2322 books = (
2323 { title = "Treasure Island"; price = 29; },
2324 { title = "Snow Crash"; price = 9; }
2325 );
2326 "#;
2327 let v: Value = from_str(config).unwrap();
2328
2329 assert_eq!(
2331 v.lookup("books.[0].title").and_then(|v| v.as_str()),
2332 Some("Treasure Island")
2333 );
2334 assert_eq!(
2335 v.lookup("books.[1].price").and_then(|v| v.as_i32()),
2336 Some(9)
2337 );
2338
2339 assert_eq!(
2341 v.lookup("books.0.title").and_then(|v| v.as_str()),
2342 Some("Treasure Island")
2343 );
2344 }
2345
2346 #[test]
2347 fn test_lookup_mut_bracket_notation() {
2348 let config = r#"items = [10, 20, 30];"#;
2349 let mut v: Value = from_str(config).unwrap();
2350
2351 *v.lookup_mut("items.[1]").unwrap() = Value::Integer(99);
2352 assert_eq!(v.lookup("items.[1]").unwrap().as_i32(), Some(99));
2353 assert_eq!(v.lookup("items.1").unwrap().as_i32(), Some(99));
2354 }
2355
2356 #[test]
2359 fn test_set_existing_key() {
2360 let mut v: Value = from_str(r#"name = "old";"#).unwrap();
2361 assert!(v.set("name", Value::String("new".to_string())).is_ok());
2362 assert_eq!(v.lookup("name").unwrap().as_str(), Some("new"));
2363 }
2364
2365 #[test]
2366 fn test_set_new_key() {
2367 let mut v: Value = from_str(r#"a = 1;"#).unwrap();
2368 assert!(v.set("b", Value::Integer(2)).is_ok());
2369 assert_eq!(v.lookup("b").unwrap().as_i32(), Some(2));
2370 }
2371
2372 #[test]
2373 fn test_set_creates_intermediate_groups() {
2374 let mut v = Value::Group(IndexMap::new());
2375 assert!(v.set("a.b.c", Value::Integer(42)).is_ok());
2376 assert_eq!(v.lookup("a.b.c").unwrap().as_i32(), Some(42));
2377 assert!(v.lookup("a").unwrap().is_group());
2378 assert!(v.lookup("a.b").unwrap().is_group());
2379 }
2380
2381 #[test]
2382 fn test_set_array_element() {
2383 let mut v: Value = from_str(r#"items = [1, 2, 3];"#).unwrap();
2384 assert!(v.set("items.[0]", Value::Integer(99)).is_ok());
2385 assert_eq!(v.lookup("items.[0]").unwrap().as_i32(), Some(99));
2386 }
2387
2388 #[test]
2389 fn test_set_array_out_of_bounds() {
2390 let mut v: Value = from_str(r#"items = [1, 2];"#).unwrap();
2391 assert!(v.set("items.[5]", Value::Integer(99)).is_err());
2392 }
2393
2394 #[test]
2395 fn test_set_on_scalar_fails() {
2396 let mut v: Value = from_str(r#"name = "hello";"#).unwrap();
2397 assert!(v.set("name.child", Value::Integer(1)).is_err());
2398 }
2399
2400 #[test]
2401 fn test_set_deeply_nested() {
2402 let mut v = Value::Group(IndexMap::new());
2403 assert!(v.set("level1.level2.level3.level4", Value::Bool(true)).is_ok());
2404 assert_eq!(
2405 v.lookup("level1.level2.level3.level4").unwrap().as_bool(),
2406 Some(true)
2407 );
2408 }
2409
2410 #[test]
2411 fn test_set_into_list_element_group() {
2412 let config = r#"
2413 books = (
2414 { title = "Old Title"; }
2415 );
2416 "#;
2417 let mut v: Value = from_str(config).unwrap();
2418 assert!(v.set("books.[0].title", Value::String("New Title".to_string())).is_ok());
2419 assert_eq!(
2420 v.lookup("books.[0].title").unwrap().as_str(),
2421 Some("New Title")
2422 );
2423 }
2424
2425 #[test]
2428 fn test_remove_group_key() {
2429 let mut v: Value = from_str(r#"a = 1; b = 2; c = 3;"#).unwrap();
2430 let removed = v.remove("b");
2431 assert_eq!(removed, Some(Value::Integer(2)));
2432 assert!(v.lookup("b").is_none());
2433 assert_eq!(v.lookup("a").unwrap().as_i32(), Some(1));
2434 assert_eq!(v.lookup("c").unwrap().as_i32(), Some(3));
2435 }
2436
2437 #[test]
2438 fn test_remove_array_element() {
2439 let mut v: Value = from_str(r#"items = [10, 20, 30];"#).unwrap();
2440 let removed = v.remove("items.[1]");
2441 assert_eq!(removed, Some(Value::Integer(20)));
2442 assert_eq!(v.lookup("items.[0]").unwrap().as_i32(), Some(10));
2444 assert_eq!(v.lookup("items.[1]").unwrap().as_i32(), Some(30));
2445 assert!(v.lookup("items.[2]").is_none());
2446 }
2447
2448 #[test]
2449 fn test_remove_nested() {
2450 let config = r#"
2451 database = {
2452 host = "localhost";
2453 port = 5432;
2454 };
2455 "#;
2456 let mut v: Value = from_str(config).unwrap();
2457 let removed = v.remove("database.host");
2458 assert_eq!(removed, Some(Value::String("localhost".to_string())));
2459 assert!(v.lookup("database.host").is_none());
2460 assert_eq!(v.lookup("database.port").unwrap().as_i32(), Some(5432));
2461 }
2462
2463 #[test]
2464 fn test_remove_nonexistent() {
2465 let mut v: Value = from_str(r#"a = 1;"#).unwrap();
2466 assert_eq!(v.remove("z"), None);
2467 assert_eq!(v.remove("a.b"), None);
2468 }
2469
2470 #[test]
2471 fn test_remove_index_out_of_bounds() {
2472 let mut v: Value = from_str(r#"items = [1, 2];"#).unwrap();
2473 assert_eq!(v.remove("items.[5]"), None);
2474 }
2475
2476 #[test]
2477 fn test_remove_entire_subtree() {
2478 let config = r#"
2479 app = {
2480 window = { title = "hi"; };
2481 debug = false;
2482 };
2483 "#;
2484 let mut v: Value = from_str(config).unwrap();
2485 let removed = v.remove("app.window");
2486 assert!(removed.unwrap().is_group());
2487 assert!(v.lookup("app.window").is_none());
2488 assert_eq!(v.lookup("app.debug").unwrap().as_bool(), Some(false));
2489 }
2490
2491 #[test]
2492 fn test_remove_bare_numeric_index() {
2493 let mut v: Value = from_str(r#"items = [10, 20, 30];"#).unwrap();
2494 let removed = v.remove("items.0");
2495 assert_eq!(removed, Some(Value::Integer(10)));
2496 assert_eq!(v.lookup("items.0").unwrap().as_i32(), Some(20));
2497 }
2498
2499 #[test]
2502 fn test_ordering_preserved_in_round_trip() {
2503 let input = r#"
2504 first = 1;
2505 second = 2;
2506 third = 3;
2507 fourth = 4;
2508"#;
2509 let v: Value = from_str(input).unwrap();
2510 let output = Config::try_from(v.clone()).unwrap().to_string().unwrap();
2511
2512 let v_output: Value = from_str(&output).unwrap();
2514 if let Value::Group(map) = v {
2515 if let Value::Group(map_output) = v_output {
2516 let keys1: Vec<&String> = map.keys().collect();
2517 let keys2: Vec<&String> = map_output.keys().collect();
2518 assert_eq!(keys1, keys2);
2519 assert_eq!(keys1, vec!["first", "second", "third", "fourth"]);
2520 }
2521 }
2522 }
2523
2524 #[test]
2525 fn test_config_implicit_no_outer_braces() {
2526 let input = "a = 1;\nb = 2;\nc = 3;";
2527 let v: Value = from_str(input).unwrap();
2528
2529 let output = Config::try_from(v).unwrap().to_string().unwrap();
2530
2531 assert!(!output.trim_start().starts_with('{'));
2533 assert!(!output.trim_end().ends_with('}'));
2534
2535 assert!(output.contains("a = 1"));
2537 assert!(output.contains("b = 2"));
2538 assert!(output.contains("c = 3"));
2539 }
2540
2541 #[test]
2542 fn test_nested_groups_have_braces() {
2543 let input = r#"
2544 outer = 1;
2545 nested = {
2546 inner = 2;
2547 };
2548"#;
2549 let v: Value = from_str(input).unwrap();
2550 let output = Config::try_from(v).unwrap().to_string().unwrap();
2551
2552 assert!(!output.trim_start().starts_with('{'));
2554
2555 assert!(output.contains("nested = {"));
2557
2558 let v2: Value = from_str(&output).unwrap();
2560 assert_eq!(v2["outer"], 1);
2561 assert_eq!(v2["nested.inner"], 2);
2562 }
2563
2564 #[test]
2565 fn test_ordering_with_mixed_types() {
2566 let input = r#"
2567 string_first = "hello";
2568 int_second = 42;
2569 bool_third = true;
2570 float_fourth = 2.25;
2571 array_fifth = [1, 2, 3];
2572"#;
2573 let v: Value = from_str(input).unwrap();
2574
2575 if let Value::Group(map) = &v {
2576 let keys: Vec<&String> = map.keys().collect();
2577 assert_eq!(
2578 keys,
2579 vec![
2580 "string_first",
2581 "int_second",
2582 "bool_third",
2583 "float_fourth",
2584 "array_fifth"
2585 ]
2586 );
2587 }
2588
2589 let output = Config::try_from(v).unwrap().to_string().unwrap();
2590 let v2: Value = from_str(&output).unwrap();
2591
2592 if let Value::Group(map) = &v2 {
2594 let keys: Vec<&String> = map.keys().collect();
2595 assert_eq!(
2596 keys,
2597 vec![
2598 "string_first",
2599 "int_second",
2600 "bool_third",
2601 "float_fourth",
2602 "array_fifth"
2603 ]
2604 );
2605 }
2606 }
2607
2608 #[test]
2609 fn test_adding_new_keys_appends_to_end() {
2610 let input = "a = 1;\nb = 2;";
2611 let mut v: Value = from_str(input).unwrap();
2612
2613 v.set("c", Value::Integer(3)).unwrap();
2615
2616 if let Value::Group(map) = &v {
2617 let keys: Vec<&String> = map.keys().collect();
2618 assert_eq!(keys, vec!["a", "b", "c"]);
2619 }
2620
2621 let output = Config::try_from(v).unwrap().to_string().unwrap();
2622
2623 let a_pos = output.find("a = 1").unwrap();
2625 let b_pos = output.find("b = 2").unwrap();
2626 let c_pos = output.find("c = 3").unwrap();
2627
2628 assert!(a_pos < b_pos);
2629 assert!(b_pos < c_pos);
2630 }
2631
2632 #[test]
2633 fn test_implicit_group_round_trip_exact() {
2634 let input = "name = \"test\";\nversion = 42;";
2635 let v: Value = from_str(input).unwrap();
2636 let output = Config::try_from(v).unwrap().to_string().unwrap();
2637
2638 assert_eq!(output, input);
2640
2641 let v2: Value = from_str(&output).unwrap();
2643 let output2 = Config::try_from(v2).unwrap().to_string().unwrap();
2644 assert_eq!(output, output2);
2645 }
2646
2647 #[test]
2648 fn test_nested_indentation() {
2649 let input = r#"
2650 outer = 1;
2651 nested = {
2652 inner = 2;
2653 deep = {
2654 value = 3;
2655 };
2656 };
2657 another = 4;
2658"#;
2659 let v: Value = from_str(input).unwrap();
2660 let output = Config::try_from(v).unwrap().to_string().unwrap();
2661
2662 assert!(output.contains("outer = 1"));
2664 assert!(output.contains("nested = {"));
2665 assert!(output.contains(" inner = 2"));
2667 assert!(output.contains(" deep = {"));
2668 assert!(output.contains(" value = 3"));
2670
2671 let v2: Value = from_str(&output).unwrap();
2673 assert_eq!(v2["outer"], 1);
2674 assert_eq!(v2["nested.inner"], 2);
2675 assert_eq!(v2["nested.deep.value"], 3);
2676 assert_eq!(v2["another"], 4);
2677 }
2678
2679 #[test]
2680 fn test_implicit_group_with_nested_explicit_groups() {
2681 let input = r#"top_level = 1;
2682nested = {
2683 inner = 2;
2684};
2685also_top = 3;"#;
2686 let v: Value = from_str(input).unwrap();
2687 let output = Config::try_from(v).unwrap().to_string().unwrap();
2688
2689 assert!(!output.trim().starts_with('{'));
2691
2692 assert!(output.contains("nested = {"));
2694 assert!(output.contains(" inner = 2"));
2695
2696 let v2: Value = from_str(&output).unwrap();
2698 assert_eq!(v2["top_level"], 1);
2699 assert_eq!(v2["nested.inner"], 2);
2700 assert_eq!(v2["also_top"], 3);
2701 }
2702
2703 #[test]
2704 fn test_deeply_nested_groups() {
2705 let input = r#"
2706 level1 = {
2707 level2 = {
2708 level3 = {
2709 value = 42;
2710 };
2711 };
2712 };
2713"#;
2714 let v: Value = from_str(input).unwrap();
2715 let output = Config::try_from(v).unwrap().to_string().unwrap();
2716
2717 assert!(output.contains("level1 = {"));
2720 assert!(output.contains(" level2 = {"));
2721 assert!(output.contains(" level3 = {"));
2722 assert!(output.contains(" value = 42"));
2723 }
2724
2725 #[test]
2728 fn test_config_implicit_round_trip() {
2729 let input = "name = \"test\";\nversion = 42;";
2730 let config = Config::from_str(input).unwrap();
2731
2732 assert_eq!(config["name"], "test");
2733 assert_eq!(config["version"], 42);
2734
2735 let output = config.to_string().unwrap();
2736 assert_eq!(output, input);
2737 }
2738
2739 #[test]
2740 fn test_config_deref_lookup() {
2741 let config = Config::from_str("a = 1; b = { c = 2; };").unwrap();
2742
2743 assert_eq!(config.lookup("b.c").unwrap().as_i32(), Some(2));
2745 assert!(config.is_group());
2746 }
2747
2748 #[test]
2749 fn test_config_deref_mut() {
2750 let mut config = Config::from_str("a = 1; b = 2;").unwrap();
2751
2752 config.set("c", Value::Integer(3)).unwrap();
2753 assert_eq!(config["c"], 3);
2754
2755 let output = config.to_string().unwrap();
2756 assert!(output.contains("c = 3"));
2757 }
2758
2759 #[test]
2760 fn test_config_display() {
2761 let config = Config::from_str("x = 10; y = 20;").unwrap();
2762 let displayed = format!("{}", config);
2763 assert!(displayed.contains("x = 10"));
2764 assert!(displayed.contains("y = 20"));
2765 assert!(!displayed.starts_with('{'));
2766 }
2767
2768 #[test]
2769 fn test_config_new_empty() {
2770 let mut config = Config::new();
2771 assert!(config.is_group());
2772
2773 config.set("key", Value::String("val".to_string())).unwrap();
2774 let output = config.to_string().unwrap();
2775 assert_eq!(output, "key = \"val\";");
2776 }
2777
2778 #[test]
2779 fn test_config_from_value() {
2780 let mut map = Map::new();
2781 map.insert("key".to_string(), Value::String("val".to_string()));
2782 let config = Config::try_from(Value::Group(map)).unwrap();
2783
2784 let output = config.to_string().unwrap();
2785 assert_eq!(output, "key = \"val\";");
2786 }
2787
2788 #[test]
2789 fn test_config_default() {
2790 let config = Config::default();
2791 assert!(config.is_group());
2792 assert_eq!(config.as_group().unwrap().len(), 0);
2793 }
2794
2795 #[test]
2796 fn test_config_serialize() {
2797 let config = Config::from_str("a = 1; b = 2;").unwrap();
2798 let serde_output = crate::to_string(&config).unwrap();
2801 assert_eq!(serde_output, "a = 1;\nb = 2;");
2802
2803 let format_output = config.to_string().unwrap();
2805 assert!(!format_output.starts_with('{'));
2806 }
2807
2808 #[test]
2809 fn test_serde_root_is_implicit_nested_is_braced() {
2810 use serde::Serialize;
2811
2812 #[derive(Serialize)]
2813 struct Inner {
2814 x: i32,
2815 }
2816 #[derive(Serialize)]
2817 struct Outer {
2818 a: i32,
2819 inner: Inner,
2820 }
2821
2822 let out = crate::to_string(&Outer {
2823 a: 1,
2824 inner: Inner { x: 2 },
2825 })
2826 .unwrap();
2827 assert_eq!(out, "a = 1;\ninner = {\n x = 2;\n};");
2829
2830 let v: Value = from_str(&out).unwrap();
2832 assert_eq!(v["a"], 1);
2833 assert_eq!(v["inner.x"], 2);
2834
2835 #[derive(Serialize)]
2837 struct Empty {}
2838 assert_eq!(crate::to_string(&Empty {}).unwrap(), "");
2839 }
2840
2841 #[test]
2842 fn test_top_level_braces_rejected() {
2843 assert!(matches!(
2846 from_str::<Value>("{ a = 1; }"),
2847 Err(e) if *e.kind() == ErrorKind::TopLevelBraces
2848 ));
2849 assert!(matches!(
2850 Config::from_str("{ a = 1; }"),
2851 Err(e) if *e.kind() == ErrorKind::TopLevelBraces
2852 ));
2853 assert!(Config::from_str("# header\n{ a = 1; }").is_err());
2855 assert!(Config::from_str("/* block */ { a = 1; }").is_err());
2856
2857 let v: Value = from_str("g = { a = 1; };").unwrap();
2859 assert_eq!(v["g.a"], 1);
2860 }
2861
2862 #[test]
2863 fn test_config_requires_group_root() {
2864 assert!(matches!(Config::from_str("42"), Err(e) if *e.kind() == ErrorKind::ExpectedGroup));
2867 assert!(matches!(Config::from_str("true"), Err(e) if *e.kind() == ErrorKind::ExpectedGroup));
2868 assert_eq!(from_str::<i32>("42").unwrap(), 42);
2869 }
2870
2871 #[test]
2872 fn test_from_value_preserves_array_vs_list() {
2873 let _warmup: Value = from_str("(1, 2)").unwrap();
2876
2877 let arr = Value::Array(vec![Value::Integer(1), Value::Integer(2)]);
2878 let round: Value = from_value(arr.clone()).unwrap();
2879 assert_eq!(round, arr);
2880 assert!(round.is_array());
2881
2882 let _warmup: Value = from_str("[1, 2]").unwrap();
2883 let list = Value::List(vec![Value::Integer(1), Value::String("a".into())]);
2884 let round: Value = from_value(list.clone()).unwrap();
2885 assert_eq!(round, list);
2886 assert!(round.is_list());
2887 }
2888
2889 #[test]
2890 fn test_from_value_enum() {
2891 use serde::Deserialize;
2892
2893 #[derive(Debug, Deserialize, PartialEq)]
2894 enum E {
2895 Unit,
2896 Newtype(i32),
2897 Struct { x: i32 },
2898 }
2899
2900 assert_eq!(
2901 from_value::<E>(Value::String("Unit".to_string())).unwrap(),
2902 E::Unit
2903 );
2904
2905 let v: Value = from_str("Newtype = 5;").unwrap();
2906 assert_eq!(from_value::<E>(v).unwrap(), E::Newtype(5));
2907
2908 let v: Value = from_str("Struct = { x = 9; };").unwrap();
2909 assert_eq!(from_value::<E>(v).unwrap(), E::Struct { x: 9 });
2910 }
2911
2912 #[test]
2913 fn test_display_is_valid_libconfig() {
2914 let v: Value = from_str(r#"s = "a\"b"; g = { n = 1; }; items = [1, 2];"#).unwrap();
2915 let displayed = format!("{}", v);
2918 let reparsed: Value = from_str(&format!("wrapped = {};", displayed)).unwrap();
2919 assert_eq!(reparsed["wrapped"], v);
2920 }
2921
2922 #[test]
2923 fn test_display_scalars() {
2924 assert_eq!(format!("{}", Value::Integer64(5)), "5L");
2925 assert_eq!(format!("{}", Value::Float(1.0)), "1.0");
2926 assert_eq!(
2927 format!("{}", Value::String("say \"hi\"".to_string())),
2928 r#""say \"hi\"""#
2929 );
2930 }
2931
2932 #[test]
2933 fn test_non_finite_float_errors_in_config_to_string() {
2934 let mut config = Config::new();
2935 config.set("bad", Value::Float(f64::NAN)).unwrap();
2936 assert!(matches!(config.to_string(), Err(e) if *e.kind() == ErrorKind::NonFiniteFloat));
2937 }
2938
2939 fn temp_dir(tag: &str) -> std::path::PathBuf {
2942 let dir = std::env::temp_dir().join(format!(
2943 "libconfigasaurus-test-{}-{}",
2944 tag,
2945 std::process::id()
2946 ));
2947 std::fs::create_dir_all(&dir).unwrap();
2948 dir
2949 }
2950
2951 #[test]
2952 fn test_include_directive() {
2953 let dir = temp_dir("basic");
2954 std::fs::write(dir.join("inner.cfg"), "b = 2;\n").unwrap();
2955 std::fs::write(
2956 dir.join("outer.cfg"),
2957 "a = 1;\n@include \"inner.cfg\"\nc = 3;\n",
2958 )
2959 .unwrap();
2960
2961 let config = Config::from_file_with_include_dir(dir.join("outer.cfg"), &dir).unwrap();
2962 assert_eq!(config["a"], 1);
2963 assert_eq!(config["b"], 2);
2964 assert_eq!(config["c"], 3);
2965
2966 std::fs::remove_dir_all(&dir).ok();
2967 }
2968
2969 #[test]
2970 fn test_include_nested_inside_group() {
2971 let dir = temp_dir("nested");
2974 std::fs::write(dir.join("quote.cfg"), "quote = \"Criticism\";\n").unwrap();
2975 std::fs::write(
2976 dir.join("test.cfg"),
2977 "info: {\n name = \"WC\";\n @include \"quote.cfg\"\n country = \"UK\";\n};\n",
2978 )
2979 .unwrap();
2980
2981 let config = Config::from_file_with_include_dir(dir.join("test.cfg"), &dir).unwrap();
2982 assert_eq!(config["info.name"], "WC");
2983 assert_eq!(config["info.quote"], "Criticism");
2984 assert_eq!(config["info.country"], "UK");
2985
2986 std::fs::remove_dir_all(&dir).ok();
2987 }
2988
2989 #[test]
2990 fn test_include_depth_limit() {
2991 let dir = temp_dir("depth");
2992 std::fs::write(dir.join("loop.cfg"), "@include \"loop.cfg\"\n").unwrap();
2993
2994 let result = Config::from_file_with_include_dir(dir.join("loop.cfg"), &dir);
2995 assert!(matches!(result, Err(e) if matches!(e.kind(), ErrorKind::Include(_))));
2996
2997 std::fs::remove_dir_all(&dir).ok();
2998 }
2999
3000 #[test]
3001 fn test_include_missing_file_errors() {
3002 let result = Config::from_str("@include \"does-not-exist-anywhere.cfg\"\n");
3003 assert!(matches!(result, Err(e) if matches!(e.kind(), ErrorKind::Include(_))));
3004 }
3005
3006 #[test]
3009 fn test_set_validates_names_and_paths() {
3010 let mut config = Config::new();
3011
3012 assert!(matches!(
3014 config.set("my key", 1).unwrap_err().kind(),
3015 ErrorKind::InvalidSettingName(_)
3016 ));
3017 assert!(matches!(
3018 config.set("2bad", 1).unwrap_err().kind(),
3019 ErrorKind::InvalidPath(_) | ErrorKind::InvalidSettingName(_)
3020 ));
3021 assert!(matches!(
3022 config.set("", 1).unwrap_err().kind(),
3023 ErrorKind::InvalidPath(_)
3024 ));
3025
3026 config.set("scalar", 5).unwrap();
3028 assert!(matches!(
3029 config.set("scalar.child", 1).unwrap_err().kind(),
3030 ErrorKind::PathTraversal(_)
3031 ));
3032 config.set("items", Value::Array(vec![Value::Integer(1)])).unwrap();
3033 assert!(matches!(
3034 config.set("items.[5]", 9).unwrap_err().kind(),
3035 ErrorKind::PathTraversal(_)
3036 ));
3037 }
3038
3039 #[test]
3040 fn test_set_accepts_into_value() {
3041 let mut config = Config::new();
3042 config.set("count", 42).unwrap();
3043 config.set("big", 5_000_000_000i64).unwrap();
3044 config.set("ratio", 0.5).unwrap();
3045 config.set("on", true).unwrap();
3046 config.set("name", "svc").unwrap();
3047 config.set("label", String::from("owned")).unwrap();
3048
3049 assert_eq!(config["count"], 42);
3050 assert_eq!(config["big"], 5_000_000_000i64);
3051 assert_eq!(config["ratio"], 0.5);
3052 assert_eq!(config["on"], true);
3053 assert_eq!(config["name"], "svc");
3054 assert_eq!(config["label"], "owned");
3055 }
3056
3057 #[test]
3058 fn test_value_from_conversions() {
3059 assert_eq!(Value::from(true), Value::Bool(true));
3060 assert_eq!(Value::from(7i32), Value::Integer(7));
3061 assert_eq!(Value::from(7u16), Value::Integer(7));
3062 assert_eq!(Value::from(7i64), Value::Integer64(7));
3063 assert_eq!(Value::from(u32::MAX), Value::Integer64(4294967295));
3065 assert_eq!(Value::from(2.5f64), Value::Float(2.5));
3066 assert_eq!(Value::from("x"), Value::String("x".to_string()));
3067 assert_eq!(Value::from(Map::new()), Value::Group(Map::new()));
3068 }
3069
3070 #[test]
3071 fn test_reverse_comparisons() {
3072 let v: Value = from_str("a = 42; s = \"hi\"; b = true; f = 2.5;").unwrap();
3073 assert!(42 == v["a"]);
3074 assert!("hi" == v["s"]);
3075 assert!(true == v["b"]);
3076 assert!(2.5 == v["f"]);
3077 let owned = String::from("hi");
3078 assert!(owned == v["s"]);
3079 }
3080
3081 #[test]
3082 fn test_mutable_accessors() {
3083 let mut v: Value = from_str("g = { a = 1; }; items = [1, 2];").unwrap();
3084
3085 v.get_mut("g")
3086 .unwrap()
3087 .as_group_mut()
3088 .unwrap()
3089 .insert("b".to_string(), Value::Integer(2));
3090 assert_eq!(v["g.b"], 2);
3091
3092 v.get_mut("items")
3093 .unwrap()
3094 .as_array_mut()
3095 .unwrap()
3096 .push(Value::Integer(3));
3097 assert_eq!(v["items.[2]"], 3);
3098
3099 *v.get_mut("items").unwrap().get_index_mut(0).unwrap() = Value::Integer(9);
3100 assert_eq!(v["items.[0]"], 9);
3101 }
3102
3103 #[test]
3104 fn test_to_value() {
3105 use serde::Serialize;
3106
3107 #[derive(Serialize)]
3108 struct Inner {
3109 x: i32,
3110 }
3111 #[derive(Serialize)]
3112 struct Outer {
3113 a: i32,
3114 names: Vec<String>,
3115 inner: Inner,
3116 things: Vec<Inner>,
3117 }
3118
3119 let v = to_value(&Outer {
3120 a: 1,
3121 names: vec!["p".into(), "q".into()],
3122 inner: Inner { x: 2 },
3123 things: vec![Inner { x: 3 }],
3124 })
3125 .unwrap();
3126
3127 assert_eq!(v["a"], 1);
3128 assert!(v["names"].is_array());
3129 assert_eq!(v["inner.x"], 2);
3130 assert!(v["things"].is_list()); assert_eq!(v["things.[0].x"], 3);
3132
3133 assert_eq!(
3135 crate::to_string(&v).unwrap(),
3136 crate::to_string(&Outer {
3137 a: 1,
3138 names: vec!["p".into(), "q".into()],
3139 inner: Inner { x: 2 },
3140 things: vec![Inner { x: 3 }],
3141 })
3142 .unwrap()
3143 );
3144
3145 assert!(matches!(
3147 to_value(&u64::MAX).unwrap_err().kind(),
3148 ErrorKind::IntegerOutOfRange
3149 ));
3150 assert!(to_value(&()).is_err());
3151 }
3152
3153 #[test]
3154 fn test_to_value_enums() {
3155 use serde::Serialize;
3156
3157 #[derive(Serialize)]
3158 enum E {
3159 Unit,
3160 Newtype(i32),
3161 Tuple(i32, bool),
3162 Struct { x: i32 },
3163 }
3164
3165 assert_eq!(to_value(&E::Unit).unwrap(), Value::String("Unit".into()));
3166 let v = to_value(&E::Newtype(5)).unwrap();
3167 assert_eq!(v["Newtype"], 5);
3168 let v = to_value(&E::Tuple(7, true)).unwrap();
3169 assert!(v["Tuple"].is_list());
3170 let v = to_value(&E::Struct { x: 9 }).unwrap();
3171 assert_eq!(v["Struct.x"], 9);
3172 }
3173
3174 #[test]
3175 fn test_option_none_fields_are_omitted() {
3176 use serde::{Deserialize, Serialize};
3177
3178 #[derive(Serialize, Deserialize, PartialEq, Debug)]
3179 struct S {
3180 a: i32,
3181 b: Option<i32>,
3182 c: Option<String>,
3183 }
3184
3185 let none = S {
3186 a: 1,
3187 b: None,
3188 c: Some("x".into()),
3189 };
3190 let text = crate::to_string(&none).unwrap();
3191 assert_eq!(text, "a = 1;\nc = \"x\";");
3193
3194 let back: S = from_str(&text).unwrap();
3196 assert_eq!(back, none);
3197
3198 let mut map: IndexMap<String, Option<i32>> = IndexMap::new();
3200 map.insert("kept".into(), Some(1));
3201 map.insert("dropped".into(), None);
3202 assert_eq!(crate::to_string(&map).unwrap(), "kept = 1;");
3203
3204 assert!(crate::to_string(&None::<i32>).is_err());
3206 assert!(crate::to_string(&(1, None::<i32>)).is_err());
3208 }
3209
3210 #[test]
3211 fn test_config_try_from_and_into_value() {
3212 let group: Value = from_str("a = 1;").unwrap();
3213 let config = Config::try_from(group.clone()).unwrap();
3214 assert_eq!(config.into_value(), group);
3215
3216 assert!(matches!(
3217 Config::try_from(Value::Integer(42)).unwrap_err().kind(),
3218 ErrorKind::ExpectedGroup
3219 ));
3220 }
3221
3222 #[test]
3223 fn test_config_root_invariant_checked_at_write() {
3224 let mut config = Config::new();
3226 *config = Value::Integer(42);
3227 assert!(matches!(
3228 config.to_string().unwrap_err().kind(),
3229 ErrorKind::ExpectedGroup
3230 ));
3231 }
3232
3233 #[test]
3234 fn test_config_deserialize() {
3235 let config: Config = from_str("a = 1; g = { b = 2; };").unwrap();
3236 assert_eq!(config["a"], 1);
3237 assert_eq!(config["g.b"], 2);
3238
3239 assert!(from_str::<Config>("42").is_err());
3240 }
3241
3242 #[test]
3243 fn test_config_to_file_round_trip() {
3244 let dir = temp_dir("tofile");
3245 let path = dir.join("out.cfg");
3246
3247 let mut config = Config::new();
3248 config.set("name", "svc").unwrap();
3249 config.set("db.port", 5432).unwrap();
3250 config.to_file(&path).unwrap();
3251
3252 let raw = std::fs::read_to_string(&path).unwrap();
3253 assert!(raw.ends_with('\n'));
3254
3255 let back = Config::from_file(&path).unwrap();
3256 assert_eq!(back, config);
3257
3258 std::fs::remove_dir_all(&dir).ok();
3259 }
3260
3261 #[test]
3262 fn test_from_reader_to_writer() {
3263 let mut buf = Vec::new();
3264 let v: Value = from_str("a = 1; b = \"x\";").unwrap();
3265 crate::to_writer(&mut buf, &v).unwrap();
3266
3267 let back: Value = crate::from_reader(buf.as_slice()).unwrap();
3268 assert_eq!(back, v);
3269 }
3270
3271 #[test]
3272 fn test_value_via_foreign_format_is_deterministic() {
3273 let _warm: Value = from_str("(1, 2)").unwrap();
3275 let v: Value = serde_json::from_str("[1, 2]").unwrap();
3278 assert!(v.is_array(), "homogeneous scalars from JSON become an array");
3279
3280 let v: Value = serde_json::from_str("[1, \"mixed\"]").unwrap();
3281 assert!(v.is_list(), "heterogeneous JSON sequences become a list");
3282
3283 let v: Value = serde_json::from_str(r#"{"a": 1}"#).unwrap();
3284 assert!(v.is_group());
3285 }
3286
3287 #[test]
3288 fn test_include_custom_resolver() {
3289 let dir = temp_dir("resolver");
3290 std::fs::write(dir.join("one.cfg"), "a = 1;\n").unwrap();
3291 std::fs::write(dir.join("two.cfg"), "b = 2;\n").unwrap();
3292
3293 let d = dir.clone();
3296 let config = Config::from_str_with_include_fn("@include \"*.cfg\"\nc = 3;\n", |path| {
3297 assert_eq!(path, "*.cfg");
3298 Ok(vec![d.join("one.cfg"), d.join("two.cfg")])
3299 })
3300 .unwrap();
3301 assert_eq!(config["a"], 1);
3302 assert_eq!(config["b"], 2);
3303 assert_eq!(config["c"], 3);
3304 let keys: Vec<&String> = config.as_group().unwrap().keys().collect();
3306 assert_eq!(keys, ["a", "b", "c"]);
3307
3308 let result = Config::from_str_with_include_fn("@include \"nope\"\n", |path| {
3310 Err(ErrorKind::Include(format!("cannot resolve '{path}'")).into())
3311 });
3312 assert!(matches!(
3313 result.unwrap_err().kind(),
3314 ErrorKind::Include(msg) if msg.contains("cannot resolve")
3315 ));
3316
3317 std::fs::write(dir.join("outer.cfg"), "@include \"inner\"\nz = 9;\n").unwrap();
3319 std::fs::write(dir.join("inner.cfg"), "y = 8;\n").unwrap();
3320 let d = dir.clone();
3321 let config =
3322 Config::from_file_with_include_fn(dir.join("outer.cfg"), move |path| {
3323 Ok(vec![d.join(format!("{path}.cfg"))])
3324 })
3325 .unwrap();
3326 assert_eq!(config["y"], 8);
3327 assert_eq!(config["z"], 9);
3328
3329 std::fs::remove_dir_all(&dir).ok();
3330 }
3331
3332 #[test]
3333 fn test_include_ignored_in_comments_and_strings() {
3334 let config = Config::from_str("/*\n@include \"nope.cfg\"\n*/\na = 1;").unwrap();
3336 assert_eq!(config["a"], 1);
3337
3338 let config = Config::from_str("s = \"see @include docs\";").unwrap();
3340 assert_eq!(config["s"], "see @include docs");
3341 }
3342}