config/
value.rs

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