config/
value.rs

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/// Underlying kind of the configuration value.
11///
12/// Standard operations on a [`Value`] by users of this crate do not require
13/// knowledge of [`ValueKind`]. Introspection of underlying kind is only required
14/// when the configuration values are unstructured or do not have known types.
15#[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/// A configuration value.
185#[derive(Default, Debug, Clone, PartialEq)]
186pub struct Value {
187    /// A description of the original location of the value.
188    ///
189    /// A Value originating from a File might contain:
190    /// ```text
191    /// Settings.toml
192    /// ```
193    ///
194    /// A Value originating from the environment would contain:
195    /// ```text
196    /// the environment
197    /// ```
198    ///
199    /// A Value originating from a remote source might contain:
200    /// ```text
201    /// etcd+http://127.0.0.1:2379
202    /// ```
203    origin: Option<String>,
204
205    /// Underlying kind of the configuration value.
206    pub kind: ValueKind,
207}
208
209impl Value {
210    /// Create a new value instance that will remember its source uri.
211    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    /// Get the description of the original location of the value.
222    pub fn origin(&self) -> Option<&str> {
223        self.origin.as_ref().map(AsRef::as_ref)
224    }
225
226    /// Attempt to deserialize this value into the requested type.
227    pub fn try_deserialize<'de, T: Deserialize<'de>>(self) -> Result<T> {
228        T::deserialize(self)
229    }
230
231    /// Returns `self` as a bool, if possible.
232    // FIXME: Should this not be `try_into_*` ?
233    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                    // Unexpected string value
248                    s => Err(ConfigError::invalid_type(
249                        self.origin.clone(),
250                        Unexpected::Str(s.into()),
251                        "a boolean",
252                    )),
253                }
254            }
255
256            // Unexpected type
257            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    /// Returns `self` into an i64, if possible.
276    // FIXME: Should this not be `try_into_*` ?
277    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                            // Unexpected string
309                            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            // Unexpected type
323            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    /// Returns `self` into an i128, if possible.
342    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                            // Unexpected string
362                            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            // Unexpected type
376            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    /// Returns `self` into an u64, if possible.
395    // FIXME: Should this not be `try_into_*` ?
396    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                            // Unexpected string
428                            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            // Unexpected type
442            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    /// Returns `self` into an u128, if possible.
461    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                            // Unexpected string
487                            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            // Unexpected type
501            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    /// Returns `self` into a f64, if possible.
520    // FIXME: Should this not be `try_into_*` ?
521    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                            // Unexpected string
532                            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            // Unexpected type
549            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    /// Returns `self` into a string, if possible.
568    // FIXME: Should this not be `try_into_*` ?
569    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            // Cannot convert
581            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    /// Returns `self` into an array, if possible
600    // FIXME: Should this not be `try_into_*` ?
601    pub fn into_array(self) -> Result<Vec<Self>> {
602        match self.kind {
603            ValueKind::Array(value) => Ok(value),
604
605            // Cannot convert
606            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    /// If the `Value` is a Table, returns the associated Map.
655    // FIXME: Should this not be `try_into_*` ?
656    pub fn into_table(self) -> Result<Map<String, Self>> {
657        match self.kind {
658            ValueKind::Table(value) => Ok(value),
659
660            // Cannot convert
661            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}