toml_edit/
value.rs

1use std::iter::FromIterator;
2use std::str::FromStr;
3
4use toml_datetime::{Date, Datetime, Time};
5
6use crate::key::Key;
7use crate::repr::{Decor, Formatted};
8use crate::{Array, InlineTable, InternalString, RawString};
9
10/// Representation of a TOML Value (as part of a Key/Value Pair).
11#[derive(Debug, Clone)]
12pub enum Value {
13    /// A string value.
14    String(Formatted<String>),
15    /// A 64-bit integer value.
16    Integer(Formatted<i64>),
17    /// A 64-bit float value.
18    Float(Formatted<f64>),
19    /// A boolean value.
20    Boolean(Formatted<bool>),
21    /// An RFC 3339 formatted date-time with offset.
22    Datetime(Formatted<Datetime>),
23    /// An inline array of values.
24    Array(Array),
25    /// An inline table of key/value pairs.
26    InlineTable(InlineTable),
27}
28
29/// Downcasting
30impl Value {
31    /// Text description of value type
32    pub fn type_name(&self) -> &'static str {
33        match self {
34            Value::String(..) => "string",
35            Value::Integer(..) => "integer",
36            Value::Float(..) => "float",
37            Value::Boolean(..) => "boolean",
38            Value::Datetime(..) => "datetime",
39            Value::Array(..) => "array",
40            Value::InlineTable(..) => "inline table",
41        }
42    }
43
44    /// Casts `self` to str.
45    pub fn as_str(&self) -> Option<&str> {
46        match *self {
47            Value::String(ref value) => Some(value.value()),
48            _ => None,
49        }
50    }
51
52    /// Returns true if `self` is a string.
53    pub fn is_str(&self) -> bool {
54        self.as_str().is_some()
55    }
56
57    /// Casts `self` to integer.
58    pub fn as_integer(&self) -> Option<i64> {
59        match *self {
60            Value::Integer(ref value) => Some(*value.value()),
61            _ => None,
62        }
63    }
64
65    /// Returns true if `self` is an integer.
66    pub fn is_integer(&self) -> bool {
67        self.as_integer().is_some()
68    }
69
70    /// Casts `self` to float.
71    pub fn as_float(&self) -> Option<f64> {
72        match *self {
73            Value::Float(ref value) => Some(*value.value()),
74            _ => None,
75        }
76    }
77
78    /// Returns true if `self` is a float.
79    pub fn is_float(&self) -> bool {
80        self.as_float().is_some()
81    }
82
83    /// Casts `self` to boolean.
84    pub fn as_bool(&self) -> Option<bool> {
85        match *self {
86            Value::Boolean(ref value) => Some(*value.value()),
87            _ => None,
88        }
89    }
90
91    /// Returns true if `self` is a boolean.
92    pub fn is_bool(&self) -> bool {
93        self.as_bool().is_some()
94    }
95
96    /// Casts `self` to date-time.
97    pub fn as_datetime(&self) -> Option<&Datetime> {
98        match *self {
99            Value::Datetime(ref value) => Some(value.value()),
100            _ => None,
101        }
102    }
103
104    /// Returns true if `self` is a date-time.
105    pub fn is_datetime(&self) -> bool {
106        self.as_datetime().is_some()
107    }
108
109    /// Casts `self` to array.
110    pub fn as_array(&self) -> Option<&Array> {
111        match *self {
112            Value::Array(ref value) => Some(value),
113            _ => None,
114        }
115    }
116
117    /// Casts `self` to mutable array.
118    pub fn as_array_mut(&mut self) -> Option<&mut Array> {
119        match *self {
120            Value::Array(ref mut value) => Some(value),
121            _ => None,
122        }
123    }
124
125    /// Returns true if `self` is an array.
126    pub fn is_array(&self) -> bool {
127        self.as_array().is_some()
128    }
129
130    /// Casts `self` to inline table.
131    pub fn as_inline_table(&self) -> Option<&InlineTable> {
132        match *self {
133            Value::InlineTable(ref value) => Some(value),
134            _ => None,
135        }
136    }
137
138    /// Casts `self` to mutable inline table.
139    pub fn as_inline_table_mut(&mut self) -> Option<&mut InlineTable> {
140        match *self {
141            Value::InlineTable(ref mut value) => Some(value),
142            _ => None,
143        }
144    }
145
146    /// Returns true if `self` is an inline table.
147    pub fn is_inline_table(&self) -> bool {
148        self.as_inline_table().is_some()
149    }
150}
151
152impl Value {
153    /// Get the decoration of the value.
154    /// # Example
155    /// ```rust
156    /// let v = toml_edit::Value::from(true);
157    /// assert_eq!(v.decor().suffix(), None);
158    ///```
159    pub fn decor_mut(&mut self) -> &mut Decor {
160        match self {
161            Value::String(f) => f.decor_mut(),
162            Value::Integer(f) => f.decor_mut(),
163            Value::Float(f) => f.decor_mut(),
164            Value::Boolean(f) => f.decor_mut(),
165            Value::Datetime(f) => f.decor_mut(),
166            Value::Array(a) => a.decor_mut(),
167            Value::InlineTable(t) => t.decor_mut(),
168        }
169    }
170
171    /// Get the decoration of the value.
172    /// # Example
173    /// ```rust
174    /// let v = toml_edit::Value::from(true);
175    /// assert_eq!(v.decor().suffix(), None);
176    ///```
177    pub fn decor(&self) -> &Decor {
178        match *self {
179            Value::String(ref f) => f.decor(),
180            Value::Integer(ref f) => f.decor(),
181            Value::Float(ref f) => f.decor(),
182            Value::Boolean(ref f) => f.decor(),
183            Value::Datetime(ref f) => f.decor(),
184            Value::Array(ref a) => a.decor(),
185            Value::InlineTable(ref t) => t.decor(),
186        }
187    }
188
189    /// Sets the prefix and the suffix for value.
190    /// # Example
191    /// ```rust
192    /// # #[cfg(feature = "display")] {
193    /// let mut v = toml_edit::Value::from(42);
194    /// assert_eq!(&v.to_string(), "42");
195    /// let d = v.decorated(" ", " ");
196    /// assert_eq!(&d.to_string(), " 42 ");
197    /// # }
198    /// ```
199    pub fn decorated(mut self, prefix: impl Into<RawString>, suffix: impl Into<RawString>) -> Self {
200        self.decorate(prefix, suffix);
201        self
202    }
203
204    pub(crate) fn decorate(&mut self, prefix: impl Into<RawString>, suffix: impl Into<RawString>) {
205        let decor = self.decor_mut();
206        *decor = Decor::new(prefix, suffix);
207    }
208
209    /// The location within the original document
210    ///
211    /// This generally requires an [`ImDocument`][crate::ImDocument].
212    pub fn span(&self) -> Option<std::ops::Range<usize>> {
213        match self {
214            Value::String(f) => f.span(),
215            Value::Integer(f) => f.span(),
216            Value::Float(f) => f.span(),
217            Value::Boolean(f) => f.span(),
218            Value::Datetime(f) => f.span(),
219            Value::Array(a) => a.span(),
220            Value::InlineTable(t) => t.span(),
221        }
222    }
223
224    pub(crate) fn despan(&mut self, input: &str) {
225        match self {
226            Value::String(f) => f.despan(input),
227            Value::Integer(f) => f.despan(input),
228            Value::Float(f) => f.despan(input),
229            Value::Boolean(f) => f.despan(input),
230            Value::Datetime(f) => f.despan(input),
231            Value::Array(a) => a.despan(input),
232            Value::InlineTable(t) => t.despan(input),
233        }
234    }
235}
236
237#[cfg(feature = "parse")]
238impl FromStr for Value {
239    type Err = crate::TomlError;
240
241    /// Parses a value from a &str
242    fn from_str(s: &str) -> Result<Self, Self::Err> {
243        crate::parser::parse_value(s)
244    }
245}
246
247impl<'b> From<&'b Value> for Value {
248    fn from(s: &'b Value) -> Self {
249        s.clone()
250    }
251}
252
253impl<'b> From<&'b str> for Value {
254    fn from(s: &'b str) -> Self {
255        s.to_owned().into()
256    }
257}
258
259impl<'b> From<&'b String> for Value {
260    fn from(s: &'b String) -> Self {
261        s.to_owned().into()
262    }
263}
264
265impl From<String> for Value {
266    fn from(s: String) -> Self {
267        Value::String(Formatted::new(s))
268    }
269}
270
271impl<'b> From<&'b InternalString> for Value {
272    fn from(s: &'b InternalString) -> Self {
273        s.as_str().into()
274    }
275}
276
277impl From<InternalString> for Value {
278    fn from(s: InternalString) -> Self {
279        s.as_str().into()
280    }
281}
282
283impl From<i64> for Value {
284    fn from(i: i64) -> Self {
285        Value::Integer(Formatted::new(i))
286    }
287}
288
289impl From<f64> for Value {
290    fn from(f: f64) -> Self {
291        // Preserve sign of NaN. It may get written to TOML as `-nan`.
292        Value::Float(Formatted::new(f))
293    }
294}
295
296impl From<bool> for Value {
297    fn from(b: bool) -> Self {
298        Value::Boolean(Formatted::new(b))
299    }
300}
301
302impl From<Datetime> for Value {
303    fn from(d: Datetime) -> Self {
304        Value::Datetime(Formatted::new(d))
305    }
306}
307
308impl From<Date> for Value {
309    fn from(d: Date) -> Self {
310        let d: Datetime = d.into();
311        d.into()
312    }
313}
314
315impl From<Time> for Value {
316    fn from(d: Time) -> Self {
317        let d: Datetime = d.into();
318        d.into()
319    }
320}
321
322impl From<Array> for Value {
323    fn from(array: Array) -> Self {
324        Value::Array(array)
325    }
326}
327
328impl From<InlineTable> for Value {
329    fn from(table: InlineTable) -> Self {
330        Value::InlineTable(table)
331    }
332}
333
334impl<V: Into<Value>> FromIterator<V> for Value {
335    fn from_iter<I>(iter: I) -> Self
336    where
337        I: IntoIterator<Item = V>,
338    {
339        let array: Array = iter.into_iter().collect();
340        Value::Array(array)
341    }
342}
343
344impl<K: Into<Key>, V: Into<Value>> FromIterator<(K, V)> for Value {
345    fn from_iter<I>(iter: I) -> Self
346    where
347        I: IntoIterator<Item = (K, V)>,
348    {
349        let table: InlineTable = iter.into_iter().collect();
350        Value::InlineTable(table)
351    }
352}
353
354#[cfg(feature = "display")]
355impl std::fmt::Display for Value {
356    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
357        crate::encode::encode_value(self, f, None, ("", ""))
358    }
359}
360
361// `key1 = value1`
362pub(crate) const DEFAULT_VALUE_DECOR: (&str, &str) = (" ", "");
363// `{ key = value }`
364pub(crate) const DEFAULT_TRAILING_VALUE_DECOR: (&str, &str) = (" ", " ");
365// `[value1, value2]`
366pub(crate) const DEFAULT_LEADING_VALUE_DECOR: (&str, &str) = ("", "");
367
368#[cfg(test)]
369#[cfg(feature = "parse")]
370#[cfg(feature = "display")]
371mod tests {
372    use super::*;
373
374    #[test]
375    fn from_iter_formatting() {
376        let features = ["node".to_owned(), "mouth".to_owned()];
377        let features: Value = features.iter().cloned().collect();
378        assert_eq!(features.to_string(), r#"["node", "mouth"]"#);
379    }
380}
381
382#[test]
383#[cfg(feature = "parse")]
384#[cfg(feature = "display")]
385fn string_roundtrip() {
386    Value::from("hello").to_string().parse::<Value>().unwrap();
387}