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