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