1use std::iter::FromIterator;
2use std::str::FromStr;
3
4use toml_datetime::*;
5
6use crate::key::Key;
7use crate::parser;
8use crate::repr::{Decor, Formatted};
9use crate::{Array, InlineTable, InternalString, RawString};
10
11/// Representation of a TOML Value (as part of a Key/Value Pair).
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 iff `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 iff `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 iff `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 iff `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 iff `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 iff `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 iff `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 /// 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 pub fn decorated(mut self, prefix: impl Into<RawString>, suffix: impl Into<RawString>) -> Self {
199 self.decorate(prefix, suffix);
200 self
201 }
202
203 pub(crate) fn decorate(&mut self, prefix: impl Into<RawString>, suffix: impl Into<RawString>) {
204 let decor = self.decor_mut();
205 *decor = Decor::new(prefix, suffix);
206 }
207
208 /// Returns the location within the original document
209 pub(crate) fn span(&self) -> Option<std::ops::Range<usize>> {
210 match self {
211 Value::String(f) => f.span(),
212 Value::Integer(f) => f.span(),
213 Value::Float(f) => f.span(),
214 Value::Boolean(f) => f.span(),
215 Value::Datetime(f) => f.span(),
216 Value::Array(a) => a.span(),
217 Value::InlineTable(t) => t.span(),
218 }
219 }
220
221 pub(crate) fn despan(&mut self, input: &str) {
222 match self {
223 Value::String(f) => f.despan(input),
224 Value::Integer(f) => f.despan(input),
225 Value::Float(f) => f.despan(input),
226 Value::Boolean(f) => f.despan(input),
227 Value::Datetime(f) => f.despan(input),
228 Value::Array(a) => a.despan(input),
229 Value::InlineTable(t) => t.despan(input),
230 }
231 }
232}
233
234impl FromStr for Value {
235 type Err = crate::TomlError;
236
237 /// Parses a value from a &str
238 fn from_str(s: &str) -> Result<Self, Self::Err> {
239 parser::parse_value(raw:s)
240 }
241}
242
243impl<'b> From<&'b Value> for Value {
244 fn from(s: &'b Value) -> Self {
245 s.clone()
246 }
247}
248
249impl<'b> From<&'b str> for Value {
250 fn from(s: &'b str) -> Self {
251 s.to_owned().into()
252 }
253}
254
255impl<'b> From<&'b String> for Value {
256 fn from(s: &'b String) -> Self {
257 s.to_owned().into()
258 }
259}
260
261impl From<String> for Value {
262 fn from(s: String) -> Self {
263 Value::String(Formatted::new(s))
264 }
265}
266
267impl<'b> From<&'b InternalString> for Value {
268 fn from(s: &'b InternalString) -> Self {
269 s.as_str().into()
270 }
271}
272
273impl From<InternalString> for Value {
274 fn from(s: InternalString) -> Self {
275 s.as_str().into()
276 }
277}
278
279impl From<i64> for Value {
280 fn from(i: i64) -> Self {
281 Value::Integer(Formatted::new(i))
282 }
283}
284
285impl From<f64> for Value {
286 fn from(f: f64) -> Self {
287 // Preserve sign of NaN. It may get written to TOML as `-nan`.
288 Value::Float(Formatted::new(f))
289 }
290}
291
292impl From<bool> for Value {
293 fn from(b: bool) -> Self {
294 Value::Boolean(Formatted::new(b))
295 }
296}
297
298impl From<Datetime> for Value {
299 fn from(d: Datetime) -> Self {
300 Value::Datetime(Formatted::new(d))
301 }
302}
303
304impl From<Date> for Value {
305 fn from(d: Date) -> Self {
306 let d: Datetime = d.into();
307 d.into()
308 }
309}
310
311impl From<Time> for Value {
312 fn from(d: Time) -> Self {
313 let d: Datetime = d.into();
314 d.into()
315 }
316}
317
318impl From<Array> for Value {
319 fn from(array: Array) -> Self {
320 Value::Array(array)
321 }
322}
323
324impl From<InlineTable> for Value {
325 fn from(table: InlineTable) -> Self {
326 Value::InlineTable(table)
327 }
328}
329
330impl<V: Into<Value>> FromIterator<V> for Value {
331 fn from_iter<I>(iter: I) -> Self
332 where
333 I: IntoIterator<Item = V>,
334 {
335 let array: Array = iter.into_iter().collect();
336 Value::Array(array)
337 }
338}
339
340impl<K: Into<Key>, V: Into<Value>> FromIterator<(K, V)> for Value {
341 fn from_iter<I>(iter: I) -> Self
342 where
343 I: IntoIterator<Item = (K, V)>,
344 {
345 let table: InlineTable = iter.into_iter().collect();
346 Value::InlineTable(table)
347 }
348}
349
350impl std::fmt::Display for Value {
351 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
352 crate::encode::Encode::encode(self, buf:f, input:None, ("", ""))
353 }
354}
355
356// `key1 = value1`
357pub(crate) const DEFAULT_VALUE_DECOR: (&str, &str) = (" ", "");
358// `{ key = value }`
359pub(crate) const DEFAULT_TRAILING_VALUE_DECOR: (&str, &str) = (" ", " ");
360// `[value1, value2]`
361pub(crate) const DEFAULT_LEADING_VALUE_DECOR: (&str, &str) = ("", "");
362
363#[cfg(test)]
364mod tests {
365 use super::*;
366
367 #[test]
368 fn from_iter_formatting() {
369 let features = vec!["node".to_owned(), "mouth".to_owned()];
370 let features: Value = features.iter().cloned().collect();
371 assert_eq!(features.to_string(), r#"["node", "mouth"]"#);
372 }
373}
374