1use std::convert::TryInto;
2use std::fmt;
3use std::fmt::Display;
4
5use serde::de::{Deserialize, Deserializer, Visitor};
6
7use crate::error::{ConfigError, Result, Unexpected};
8use crate::map::Map;
9
10#[derive(Debug, Clone, PartialEq)]
16pub enum ValueKind {
17 Nil,
18 Boolean(bool),
19 I64(i64),
20 I128(i128),
21 U64(u64),
22 U128(u128),
23 Float(f64),
24 String(String),
25 Table(Table),
26 Array(Array),
27}
28
29pub(crate) type Array = Vec<Value>;
30pub(crate) type Table = Map<String, Value>;
31
32impl Default for ValueKind {
33 fn default() -> Self {
34 Self::Nil
35 }
36}
37
38impl<T> From<Option<T>> for ValueKind
39where
40 T: Into<Self>,
41{
42 fn from(value: Option<T>) -> Self {
43 match value {
44 Some(value) => value.into(),
45 None => Self::Nil,
46 }
47 }
48}
49
50impl From<String> for ValueKind {
51 fn from(value: String) -> Self {
52 Self::String(value)
53 }
54}
55
56impl<'a> From<&'a str> for ValueKind {
57 fn from(value: &'a str) -> Self {
58 Self::String(value.into())
59 }
60}
61
62impl From<i8> for ValueKind {
63 fn from(value: i8) -> Self {
64 Self::I64(value.into())
65 }
66}
67
68impl From<i16> for ValueKind {
69 fn from(value: i16) -> Self {
70 Self::I64(value.into())
71 }
72}
73
74impl From<i32> for ValueKind {
75 fn from(value: i32) -> Self {
76 Self::I64(value.into())
77 }
78}
79
80impl From<i64> for ValueKind {
81 fn from(value: i64) -> Self {
82 Self::I64(value)
83 }
84}
85
86impl From<i128> for ValueKind {
87 fn from(value: i128) -> Self {
88 Self::I128(value)
89 }
90}
91
92impl From<u8> for ValueKind {
93 fn from(value: u8) -> Self {
94 Self::U64(value.into())
95 }
96}
97
98impl From<u16> for ValueKind {
99 fn from(value: u16) -> Self {
100 Self::U64(value.into())
101 }
102}
103
104impl From<u32> for ValueKind {
105 fn from(value: u32) -> Self {
106 Self::U64(value.into())
107 }
108}
109
110impl From<u64> for ValueKind {
111 fn from(value: u64) -> Self {
112 Self::U64(value)
113 }
114}
115
116impl From<u128> for ValueKind {
117 fn from(value: u128) -> Self {
118 Self::U128(value)
119 }
120}
121
122impl From<f64> for ValueKind {
123 fn from(value: f64) -> Self {
124 Self::Float(value)
125 }
126}
127
128impl From<bool> for ValueKind {
129 fn from(value: bool) -> Self {
130 Self::Boolean(value)
131 }
132}
133
134impl<T> From<Map<String, T>> for ValueKind
135where
136 T: Into<Value>,
137{
138 fn from(values: Map<String, T>) -> Self {
139 let t = values.into_iter().map(|(k, v)| (k, v.into())).collect();
140 Self::Table(t)
141 }
142}
143
144impl<T> From<Vec<T>> for ValueKind
145where
146 T: Into<Value>,
147{
148 fn from(values: Vec<T>) -> Self {
149 Self::Array(values.into_iter().map(T::into).collect())
150 }
151}
152
153impl Display for ValueKind {
154 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
155 use std::fmt::Write;
156
157 match *self {
158 Self::String(ref value) => write!(f, "{value}"),
159 Self::Boolean(value) => write!(f, "{value}"),
160 Self::I64(value) => write!(f, "{value}"),
161 Self::I128(value) => write!(f, "{value}"),
162 Self::U64(value) => write!(f, "{value}"),
163 Self::U128(value) => write!(f, "{value}"),
164 Self::Float(value) => write!(f, "{value}"),
165 Self::Nil => write!(f, "nil"),
166 Self::Table(ref table) => {
167 let mut s = String::new();
168 for (k, v) in table.iter() {
169 write!(s, "{k} => {v}, ")?;
170 }
171 write!(f, "{{ {s} }}")
172 }
173 Self::Array(ref array) => {
174 let mut s = String::new();
175 for e in array.iter() {
176 write!(s, "{e}, ")?;
177 }
178 write!(f, "{s:?}")
179 }
180 }
181 }
182}
183
184#[derive(Default, Debug, Clone, PartialEq)]
186pub struct Value {
187 origin: Option<String>,
204
205 pub kind: ValueKind,
207}
208
209impl Value {
210 pub fn new<V>(origin: Option<&String>, kind: V) -> Self
212 where
213 V: Into<ValueKind>,
214 {
215 Self {
216 origin: origin.cloned(),
217 kind: kind.into(),
218 }
219 }
220
221 pub fn origin(&self) -> Option<&str> {
223 self.origin.as_ref().map(AsRef::as_ref)
224 }
225
226 pub fn try_deserialize<'de, T: Deserialize<'de>>(self) -> Result<T> {
228 T::deserialize(self)
229 }
230
231 pub fn into_bool(self) -> Result<bool> {
234 match self.kind {
235 ValueKind::Boolean(value) => Ok(value),
236 ValueKind::I64(value) => Ok(value != 0),
237 ValueKind::I128(value) => Ok(value != 0),
238 ValueKind::U64(value) => Ok(value != 0),
239 ValueKind::U128(value) => Ok(value != 0),
240 ValueKind::Float(value) => Ok(value != 0.0),
241
242 ValueKind::String(ref value) => {
243 match value.to_lowercase().as_ref() {
244 "1" | "true" | "on" | "yes" => Ok(true),
245 "0" | "false" | "off" | "no" => Ok(false),
246
247 s => Err(ConfigError::invalid_type(
249 self.origin.clone(),
250 Unexpected::Str(s.into()),
251 "a boolean",
252 )),
253 }
254 }
255
256 ValueKind::Nil => Err(ConfigError::invalid_type(
258 self.origin,
259 Unexpected::Unit,
260 "a boolean",
261 )),
262 ValueKind::Table(_) => Err(ConfigError::invalid_type(
263 self.origin,
264 Unexpected::Map,
265 "a boolean",
266 )),
267 ValueKind::Array(_) => Err(ConfigError::invalid_type(
268 self.origin,
269 Unexpected::Seq,
270 "a boolean",
271 )),
272 }
273 }
274
275 pub fn into_int(self) -> Result<i64> {
278 match self.kind {
279 ValueKind::I64(value) => Ok(value),
280 ValueKind::I128(value) => value.try_into().map_err(|_| {
281 ConfigError::invalid_type(
282 self.origin,
283 Unexpected::I128(value),
284 "an signed 64 bit or less integer",
285 )
286 }),
287 ValueKind::U64(value) => value.try_into().map_err(|_| {
288 ConfigError::invalid_type(
289 self.origin,
290 Unexpected::U64(value),
291 "an signed 64 bit or less integer",
292 )
293 }),
294 ValueKind::U128(value) => value.try_into().map_err(|_| {
295 ConfigError::invalid_type(
296 self.origin,
297 Unexpected::U128(value),
298 "an signed 64 bit or less integer",
299 )
300 }),
301
302 ValueKind::String(ref s) => {
303 match s.to_lowercase().as_ref() {
304 "true" | "on" | "yes" => Ok(1),
305 "false" | "off" | "no" => Ok(0),
306 _ => {
307 s.parse().map_err(|_| {
308 ConfigError::invalid_type(
310 self.origin.clone(),
311 Unexpected::Str(s.clone()),
312 "an integer",
313 )
314 })
315 }
316 }
317 }
318
319 ValueKind::Boolean(value) => Ok(i64::from(value)),
320 ValueKind::Float(value) => Ok(value.round() as i64),
321
322 ValueKind::Nil => Err(ConfigError::invalid_type(
324 self.origin,
325 Unexpected::Unit,
326 "an integer",
327 )),
328 ValueKind::Table(_) => Err(ConfigError::invalid_type(
329 self.origin,
330 Unexpected::Map,
331 "an integer",
332 )),
333 ValueKind::Array(_) => Err(ConfigError::invalid_type(
334 self.origin,
335 Unexpected::Seq,
336 "an integer",
337 )),
338 }
339 }
340
341 pub fn into_int128(self) -> Result<i128> {
343 match self.kind {
344 ValueKind::I64(value) => Ok(value.into()),
345 ValueKind::I128(value) => Ok(value),
346 ValueKind::U64(value) => Ok(value.into()),
347 ValueKind::U128(value) => value.try_into().map_err(|_| {
348 ConfigError::invalid_type(
349 self.origin,
350 Unexpected::U128(value),
351 "an signed 128 bit integer",
352 )
353 }),
354
355 ValueKind::String(ref s) => {
356 match s.to_lowercase().as_ref() {
357 "true" | "on" | "yes" => Ok(1),
358 "false" | "off" | "no" => Ok(0),
359 _ => {
360 s.parse().map_err(|_| {
361 ConfigError::invalid_type(
363 self.origin.clone(),
364 Unexpected::Str(s.clone()),
365 "an integer",
366 )
367 })
368 }
369 }
370 }
371
372 ValueKind::Boolean(value) => Ok(i128::from(value)),
373 ValueKind::Float(value) => Ok(value.round() as i128),
374
375 ValueKind::Nil => Err(ConfigError::invalid_type(
377 self.origin,
378 Unexpected::Unit,
379 "an integer",
380 )),
381 ValueKind::Table(_) => Err(ConfigError::invalid_type(
382 self.origin,
383 Unexpected::Map,
384 "an integer",
385 )),
386 ValueKind::Array(_) => Err(ConfigError::invalid_type(
387 self.origin,
388 Unexpected::Seq,
389 "an integer",
390 )),
391 }
392 }
393
394 pub fn into_uint(self) -> Result<u64> {
397 match self.kind {
398 ValueKind::U64(value) => Ok(value),
399 ValueKind::U128(value) => value.try_into().map_err(|_| {
400 ConfigError::invalid_type(
401 self.origin,
402 Unexpected::U128(value),
403 "an unsigned 64 bit or less integer",
404 )
405 }),
406 ValueKind::I64(value) => value.try_into().map_err(|_| {
407 ConfigError::invalid_type(
408 self.origin,
409 Unexpected::I64(value),
410 "an unsigned 64 bit or less integer",
411 )
412 }),
413 ValueKind::I128(value) => value.try_into().map_err(|_| {
414 ConfigError::invalid_type(
415 self.origin,
416 Unexpected::I128(value),
417 "an unsigned 64 bit or less integer",
418 )
419 }),
420
421 ValueKind::String(ref s) => {
422 match s.to_lowercase().as_ref() {
423 "true" | "on" | "yes" => Ok(1),
424 "false" | "off" | "no" => Ok(0),
425 _ => {
426 s.parse().map_err(|_| {
427 ConfigError::invalid_type(
429 self.origin.clone(),
430 Unexpected::Str(s.clone()),
431 "an integer",
432 )
433 })
434 }
435 }
436 }
437
438 ValueKind::Boolean(value) => Ok(u64::from(value)),
439 ValueKind::Float(value) => Ok(value.round() as u64),
440
441 ValueKind::Nil => Err(ConfigError::invalid_type(
443 self.origin,
444 Unexpected::Unit,
445 "an integer",
446 )),
447 ValueKind::Table(_) => Err(ConfigError::invalid_type(
448 self.origin,
449 Unexpected::Map,
450 "an integer",
451 )),
452 ValueKind::Array(_) => Err(ConfigError::invalid_type(
453 self.origin,
454 Unexpected::Seq,
455 "an integer",
456 )),
457 }
458 }
459
460 pub fn into_uint128(self) -> Result<u128> {
462 match self.kind {
463 ValueKind::U64(value) => Ok(value.into()),
464 ValueKind::U128(value) => Ok(value),
465 ValueKind::I64(value) => value.try_into().map_err(|_| {
466 ConfigError::invalid_type(
467 self.origin,
468 Unexpected::I64(value),
469 "an unsigned 128 bit or less integer",
470 )
471 }),
472 ValueKind::I128(value) => value.try_into().map_err(|_| {
473 ConfigError::invalid_type(
474 self.origin,
475 Unexpected::I128(value),
476 "an unsigned 128 bit or less integer",
477 )
478 }),
479
480 ValueKind::String(ref s) => {
481 match s.to_lowercase().as_ref() {
482 "true" | "on" | "yes" => Ok(1),
483 "false" | "off" | "no" => Ok(0),
484 _ => {
485 s.parse().map_err(|_| {
486 ConfigError::invalid_type(
488 self.origin.clone(),
489 Unexpected::Str(s.clone()),
490 "an integer",
491 )
492 })
493 }
494 }
495 }
496
497 ValueKind::Boolean(value) => Ok(u128::from(value)),
498 ValueKind::Float(value) => Ok(value.round() as u128),
499
500 ValueKind::Nil => Err(ConfigError::invalid_type(
502 self.origin,
503 Unexpected::Unit,
504 "an integer",
505 )),
506 ValueKind::Table(_) => Err(ConfigError::invalid_type(
507 self.origin,
508 Unexpected::Map,
509 "an integer",
510 )),
511 ValueKind::Array(_) => Err(ConfigError::invalid_type(
512 self.origin,
513 Unexpected::Seq,
514 "an integer",
515 )),
516 }
517 }
518
519 pub fn into_float(self) -> Result<f64> {
522 match self.kind {
523 ValueKind::Float(value) => Ok(value),
524
525 ValueKind::String(ref s) => {
526 match s.to_lowercase().as_ref() {
527 "true" | "on" | "yes" => Ok(1.0),
528 "false" | "off" | "no" => Ok(0.0),
529 _ => {
530 s.parse().map_err(|_| {
531 ConfigError::invalid_type(
533 self.origin.clone(),
534 Unexpected::Str(s.clone()),
535 "a floating point",
536 )
537 })
538 }
539 }
540 }
541
542 ValueKind::I64(value) => Ok(value as f64),
543 ValueKind::I128(value) => Ok(value as f64),
544 ValueKind::U64(value) => Ok(value as f64),
545 ValueKind::U128(value) => Ok(value as f64),
546 ValueKind::Boolean(value) => Ok(if value { 1.0 } else { 0.0 }),
547
548 ValueKind::Nil => Err(ConfigError::invalid_type(
550 self.origin,
551 Unexpected::Unit,
552 "a floating point",
553 )),
554 ValueKind::Table(_) => Err(ConfigError::invalid_type(
555 self.origin,
556 Unexpected::Map,
557 "a floating point",
558 )),
559 ValueKind::Array(_) => Err(ConfigError::invalid_type(
560 self.origin,
561 Unexpected::Seq,
562 "a floating point",
563 )),
564 }
565 }
566
567 pub fn into_string(self) -> Result<String> {
570 match self.kind {
571 ValueKind::String(value) => Ok(value),
572
573 ValueKind::Boolean(value) => Ok(value.to_string()),
574 ValueKind::I64(value) => Ok(value.to_string()),
575 ValueKind::I128(value) => Ok(value.to_string()),
576 ValueKind::U64(value) => Ok(value.to_string()),
577 ValueKind::U128(value) => Ok(value.to_string()),
578 ValueKind::Float(value) => Ok(value.to_string()),
579
580 ValueKind::Nil => Err(ConfigError::invalid_type(
582 self.origin,
583 Unexpected::Unit,
584 "a string",
585 )),
586 ValueKind::Table(_) => Err(ConfigError::invalid_type(
587 self.origin,
588 Unexpected::Map,
589 "a string",
590 )),
591 ValueKind::Array(_) => Err(ConfigError::invalid_type(
592 self.origin,
593 Unexpected::Seq,
594 "a string",
595 )),
596 }
597 }
598
599 pub fn into_array(self) -> Result<Vec<Self>> {
602 match self.kind {
603 ValueKind::Array(value) => Ok(value),
604
605 ValueKind::Float(value) => Err(ConfigError::invalid_type(
607 self.origin,
608 Unexpected::Float(value),
609 "an array",
610 )),
611 ValueKind::String(value) => Err(ConfigError::invalid_type(
612 self.origin,
613 Unexpected::Str(value),
614 "an array",
615 )),
616 ValueKind::I64(value) => Err(ConfigError::invalid_type(
617 self.origin,
618 Unexpected::I64(value),
619 "an array",
620 )),
621 ValueKind::I128(value) => Err(ConfigError::invalid_type(
622 self.origin,
623 Unexpected::I128(value),
624 "an array",
625 )),
626 ValueKind::U64(value) => Err(ConfigError::invalid_type(
627 self.origin,
628 Unexpected::U64(value),
629 "an array",
630 )),
631 ValueKind::U128(value) => Err(ConfigError::invalid_type(
632 self.origin,
633 Unexpected::U128(value),
634 "an array",
635 )),
636 ValueKind::Boolean(value) => Err(ConfigError::invalid_type(
637 self.origin,
638 Unexpected::Bool(value),
639 "an array",
640 )),
641 ValueKind::Nil => Err(ConfigError::invalid_type(
642 self.origin,
643 Unexpected::Unit,
644 "an array",
645 )),
646 ValueKind::Table(_) => Err(ConfigError::invalid_type(
647 self.origin,
648 Unexpected::Map,
649 "an array",
650 )),
651 }
652 }
653
654 pub fn into_table(self) -> Result<Map<String, Self>> {
657 match self.kind {
658 ValueKind::Table(value) => Ok(value),
659
660 ValueKind::Float(value) => Err(ConfigError::invalid_type(
662 self.origin,
663 Unexpected::Float(value),
664 "a map",
665 )),
666 ValueKind::String(value) => Err(ConfigError::invalid_type(
667 self.origin,
668 Unexpected::Str(value),
669 "a map",
670 )),
671 ValueKind::I64(value) => Err(ConfigError::invalid_type(
672 self.origin,
673 Unexpected::I64(value),
674 "a map",
675 )),
676 ValueKind::I128(value) => Err(ConfigError::invalid_type(
677 self.origin,
678 Unexpected::I128(value),
679 "a map",
680 )),
681 ValueKind::U64(value) => Err(ConfigError::invalid_type(
682 self.origin,
683 Unexpected::U64(value),
684 "a map",
685 )),
686 ValueKind::U128(value) => Err(ConfigError::invalid_type(
687 self.origin,
688 Unexpected::U128(value),
689 "a map",
690 )),
691 ValueKind::Boolean(value) => Err(ConfigError::invalid_type(
692 self.origin,
693 Unexpected::Bool(value),
694 "a map",
695 )),
696 ValueKind::Nil => Err(ConfigError::invalid_type(
697 self.origin,
698 Unexpected::Unit,
699 "a map",
700 )),
701 ValueKind::Array(_) => Err(ConfigError::invalid_type(
702 self.origin,
703 Unexpected::Seq,
704 "a map",
705 )),
706 }
707 }
708}
709
710impl<'de> Deserialize<'de> for Value {
711 #[inline]
712 fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
713 where
714 D: Deserializer<'de>,
715 {
716 struct ValueVisitor;
717
718 impl<'de> Visitor<'de> for ValueVisitor {
719 type Value = Value;
720
721 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
722 formatter.write_str("any valid configuration value")
723 }
724
725 #[inline]
726 fn visit_bool<E>(self, value: bool) -> ::std::result::Result<Value, E> {
727 Ok(value.into())
728 }
729
730 #[inline]
731 fn visit_i8<E>(self, value: i8) -> ::std::result::Result<Value, E> {
732 Ok((i64::from(value)).into())
733 }
734
735 #[inline]
736 fn visit_i16<E>(self, value: i16) -> ::std::result::Result<Value, E> {
737 Ok((i64::from(value)).into())
738 }
739
740 #[inline]
741 fn visit_i32<E>(self, value: i32) -> ::std::result::Result<Value, E> {
742 Ok((i64::from(value)).into())
743 }
744
745 #[inline]
746 fn visit_i64<E>(self, value: i64) -> ::std::result::Result<Value, E> {
747 Ok(value.into())
748 }
749
750 #[inline]
751 fn visit_i128<E>(self, value: i128) -> ::std::result::Result<Value, E> {
752 Ok(value.into())
753 }
754
755 #[inline]
756 fn visit_u8<E>(self, value: u8) -> ::std::result::Result<Value, E> {
757 Ok((i64::from(value)).into())
758 }
759
760 #[inline]
761 fn visit_u16<E>(self, value: u16) -> ::std::result::Result<Value, E> {
762 Ok((i64::from(value)).into())
763 }
764
765 #[inline]
766 fn visit_u32<E>(self, value: u32) -> ::std::result::Result<Value, E> {
767 Ok((i64::from(value)).into())
768 }
769
770 #[inline]
771 fn visit_u64<E>(self, value: u64) -> ::std::result::Result<Value, E>
772 where
773 E: ::serde::de::Error,
774 {
775 let num: i64 = value.try_into().map_err(|_| {
776 E::invalid_type(::serde::de::Unexpected::Unsigned(value), &self)
777 })?;
778 Ok(num.into())
779 }
780
781 #[inline]
782 fn visit_u128<E>(self, value: u128) -> ::std::result::Result<Value, E>
783 where
784 E: ::serde::de::Error,
785 {
786 let num: i128 = value.try_into().map_err(|_| {
787 E::invalid_type(
788 ::serde::de::Unexpected::Other(
789 format!("integer `{value}` as u128").as_str(),
790 ),
791 &self,
792 )
793 })?;
794 Ok(num.into())
795 }
796
797 #[inline]
798 fn visit_f64<E>(self, value: f64) -> ::std::result::Result<Value, E> {
799 Ok(value.into())
800 }
801
802 #[inline]
803 fn visit_str<E>(self, value: &str) -> ::std::result::Result<Value, E>
804 where
805 E: ::serde::de::Error,
806 {
807 self.visit_string(String::from(value))
808 }
809
810 #[inline]
811 fn visit_string<E>(self, value: String) -> ::std::result::Result<Value, E> {
812 Ok(value.into())
813 }
814
815 #[inline]
816 fn visit_none<E>(self) -> ::std::result::Result<Value, E> {
817 Ok(Value::new(None, ValueKind::Nil))
818 }
819
820 #[inline]
821 fn visit_some<D>(self, deserializer: D) -> ::std::result::Result<Value, D::Error>
822 where
823 D: Deserializer<'de>,
824 {
825 Deserialize::deserialize(deserializer)
826 }
827
828 #[inline]
829 fn visit_unit<E>(self) -> ::std::result::Result<Value, E> {
830 Ok(Value::new(None, ValueKind::Nil))
831 }
832
833 #[inline]
834 fn visit_seq<V>(self, mut visitor: V) -> ::std::result::Result<Value, V::Error>
835 where
836 V: ::serde::de::SeqAccess<'de>,
837 {
838 let mut vec = Array::new();
839
840 while let Some(elem) = visitor.next_element()? {
841 vec.push(elem);
842 }
843
844 Ok(vec.into())
845 }
846
847 fn visit_map<V>(self, mut visitor: V) -> ::std::result::Result<Value, V::Error>
848 where
849 V: ::serde::de::MapAccess<'de>,
850 {
851 let mut values = Table::new();
852
853 while let Some((key, value)) = visitor.next_entry()? {
854 values.insert(key, value);
855 }
856
857 Ok(values.into())
858 }
859 }
860
861 deserializer.deserialize_any(ValueVisitor)
862 }
863}
864
865impl<T> From<T> for Value
866where
867 T: Into<ValueKind>,
868{
869 fn from(value: T) -> Self {
870 Self {
871 origin: None,
872 kind: value.into(),
873 }
874 }
875}
876
877impl Display for Value {
878 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
879 write!(f, "{}", self.kind)
880 }
881}
882
883#[cfg(test)]
884mod tests {
885 use super::ValueKind;
886 use crate::Config;
887 use crate::File;
888 use crate::FileFormat;
889
890 #[test]
891 #[cfg(feature = "toml")]
892 fn test_i64() {
893 let c = Config::builder()
894 .add_source(File::from_str(
895 "
896value = 120
897",
898 FileFormat::Toml,
899 ))
900 .build()
901 .unwrap();
902
903 assert!(std::matches!(c.cache.kind, ValueKind::Table(_)));
904 let v = match c.cache.kind {
905 ValueKind::Table(t) => t,
906 _ => unreachable!(),
907 };
908
909 let value = v.get("value").unwrap();
910 assert!(
911 std::matches!(value.kind, ValueKind::I64(120)),
912 "Is not a i64(120): {:?}",
913 value.kind
914 );
915 }
916}