• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use std::iter::FromIterator;
2 use std::str::FromStr;
3 
4 use toml_datetime::{Date, Datetime, Time};
5 
6 use crate::key::Key;
7 use crate::repr::{Decor, Formatted};
8 use crate::{Array, InlineTable, InternalString, RawString};
9 
10 /// Representation of a TOML Value (as part of a Key/Value Pair).
11 #[derive(Debug, Clone)]
12 pub 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
30 impl Value {
31     /// Text description of value type
type_name(&self) -> &'static str32     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.
as_str(&self) -> Option<&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.
is_str(&self) -> bool53     pub fn is_str(&self) -> bool {
54         self.as_str().is_some()
55     }
56 
57     /// Casts `self` to integer.
as_integer(&self) -> Option<i64>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.
is_integer(&self) -> bool66     pub fn is_integer(&self) -> bool {
67         self.as_integer().is_some()
68     }
69 
70     /// Casts `self` to float.
as_float(&self) -> Option<f64>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.
is_float(&self) -> bool79     pub fn is_float(&self) -> bool {
80         self.as_float().is_some()
81     }
82 
83     /// Casts `self` to boolean.
as_bool(&self) -> Option<bool>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.
is_bool(&self) -> bool92     pub fn is_bool(&self) -> bool {
93         self.as_bool().is_some()
94     }
95 
96     /// Casts `self` to date-time.
as_datetime(&self) -> Option<&Datetime>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.
is_datetime(&self) -> bool105     pub fn is_datetime(&self) -> bool {
106         self.as_datetime().is_some()
107     }
108 
109     /// Casts `self` to array.
as_array(&self) -> Option<&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.
as_array_mut(&mut self) -> Option<&mut 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.
is_array(&self) -> bool126     pub fn is_array(&self) -> bool {
127         self.as_array().is_some()
128     }
129 
130     /// Casts `self` to inline table.
as_inline_table(&self) -> Option<&InlineTable>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.
as_inline_table_mut(&mut self) -> Option<&mut InlineTable>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.
is_inline_table(&self) -> bool147     pub fn is_inline_table(&self) -> bool {
148         self.as_inline_table().is_some()
149     }
150 }
151 
152 impl 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     ///```
decor_mut(&mut self) -> &mut Decor159     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     ///```
decor(&self) -> &Decor177     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     /// ```
decorated(mut self, prefix: impl Into<RawString>, suffix: impl Into<RawString>) -> Self199     pub fn decorated(mut self, prefix: impl Into<RawString>, suffix: impl Into<RawString>) -> Self {
200         self.decorate(prefix, suffix);
201         self
202     }
203 
decorate(&mut self, prefix: impl Into<RawString>, suffix: impl Into<RawString>)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].
span(&self) -> Option<std::ops::Range<usize>>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 
despan(&mut self, input: &str)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")]
238 impl FromStr for Value {
239     type Err = crate::TomlError;
240 
241     /// Parses a value from a &str
from_str(s: &str) -> Result<Self, Self::Err>242     fn from_str(s: &str) -> Result<Self, Self::Err> {
243         crate::parser::parse_value(s)
244     }
245 }
246 
247 impl<'b> From<&'b Value> for Value {
from(s: &'b Value) -> Self248     fn from(s: &'b Value) -> Self {
249         s.clone()
250     }
251 }
252 
253 impl<'b> From<&'b str> for Value {
from(s: &'b str) -> Self254     fn from(s: &'b str) -> Self {
255         s.to_owned().into()
256     }
257 }
258 
259 impl<'b> From<&'b String> for Value {
from(s: &'b String) -> Self260     fn from(s: &'b String) -> Self {
261         s.to_owned().into()
262     }
263 }
264 
265 impl From<String> for Value {
from(s: String) -> Self266     fn from(s: String) -> Self {
267         Value::String(Formatted::new(s))
268     }
269 }
270 
271 impl<'b> From<&'b InternalString> for Value {
from(s: &'b InternalString) -> Self272     fn from(s: &'b InternalString) -> Self {
273         s.as_str().into()
274     }
275 }
276 
277 impl From<InternalString> for Value {
from(s: InternalString) -> Self278     fn from(s: InternalString) -> Self {
279         s.as_str().into()
280     }
281 }
282 
283 impl From<i64> for Value {
from(i: i64) -> Self284     fn from(i: i64) -> Self {
285         Value::Integer(Formatted::new(i))
286     }
287 }
288 
289 impl From<f64> for Value {
from(f: f64) -> Self290     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 
296 impl From<bool> for Value {
from(b: bool) -> Self297     fn from(b: bool) -> Self {
298         Value::Boolean(Formatted::new(b))
299     }
300 }
301 
302 impl From<Datetime> for Value {
from(d: Datetime) -> Self303     fn from(d: Datetime) -> Self {
304         Value::Datetime(Formatted::new(d))
305     }
306 }
307 
308 impl From<Date> for Value {
from(d: Date) -> Self309     fn from(d: Date) -> Self {
310         let d: Datetime = d.into();
311         d.into()
312     }
313 }
314 
315 impl From<Time> for Value {
from(d: Time) -> Self316     fn from(d: Time) -> Self {
317         let d: Datetime = d.into();
318         d.into()
319     }
320 }
321 
322 impl From<Array> for Value {
from(array: Array) -> Self323     fn from(array: Array) -> Self {
324         Value::Array(array)
325     }
326 }
327 
328 impl From<InlineTable> for Value {
from(table: InlineTable) -> Self329     fn from(table: InlineTable) -> Self {
330         Value::InlineTable(table)
331     }
332 }
333 
334 impl<V: Into<Value>> FromIterator<V> for Value {
from_iter<I>(iter: I) -> Self where I: IntoIterator<Item = V>,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 
344 impl<K: Into<Key>, V: Into<Value>> FromIterator<(K, V)> for Value {
from_iter<I>(iter: I) -> Self where I: IntoIterator<Item = (K, V)>,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")]
355 impl std::fmt::Display for Value {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result356     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`
362 pub(crate) const DEFAULT_VALUE_DECOR: (&str, &str) = (" ", "");
363 // `{ key = value }`
364 pub(crate) const DEFAULT_TRAILING_VALUE_DECOR: (&str, &str) = (" ", " ");
365 // `[value1, value2]`
366 pub(crate) const DEFAULT_LEADING_VALUE_DECOR: (&str, &str) = ("", "");
367 
368 #[cfg(test)]
369 #[cfg(feature = "parse")]
370 #[cfg(feature = "display")]
371 mod tests {
372     use super::*;
373 
374     #[test]
from_iter_formatting()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")]
string_roundtrip()385 fn string_roundtrip() {
386     Value::from("hello").to_string().parse::<Value>().unwrap();
387 }
388