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, RawString};
9
10#[derive(Debug, Clone)]
13pub enum Value {
14 String(Formatted<String>),
16 Integer(Formatted<i64>),
18 Float(Formatted<f64>),
20 Boolean(Formatted<bool>),
22 Datetime(Formatted<Datetime>),
24 Array(Array),
26 InlineTable(InlineTable),
28}
29
30impl Value {
32 pub fn type_name(&self) -> &'static str {
34 match self {
35 Self::String(..) => "string",
36 Self::Integer(..) => "integer",
37 Self::Float(..) => "float",
38 Self::Boolean(..) => "boolean",
39 Self::Datetime(..) => "datetime",
40 Self::Array(..) => "array",
41 Self::InlineTable(..) => "inline table",
42 }
43 }
44
45 pub fn as_str(&self) -> Option<&str> {
47 match *self {
48 Self::String(ref value) => Some(value.value()),
49 _ => None,
50 }
51 }
52
53 pub fn is_str(&self) -> bool {
55 self.as_str().is_some()
56 }
57
58 pub fn as_integer(&self) -> Option<i64> {
60 match *self {
61 Self::Integer(ref value) => Some(*value.value()),
62 _ => None,
63 }
64 }
65
66 pub fn is_integer(&self) -> bool {
68 self.as_integer().is_some()
69 }
70
71 pub fn as_float(&self) -> Option<f64> {
73 match *self {
74 Self::Float(ref value) => Some(*value.value()),
75 _ => None,
76 }
77 }
78
79 pub fn is_float(&self) -> bool {
81 self.as_float().is_some()
82 }
83
84 pub fn as_bool(&self) -> Option<bool> {
86 match *self {
87 Self::Boolean(ref value) => Some(*value.value()),
88 _ => None,
89 }
90 }
91
92 pub fn is_bool(&self) -> bool {
94 self.as_bool().is_some()
95 }
96
97 pub fn as_datetime(&self) -> Option<&Datetime> {
99 match *self {
100 Self::Datetime(ref value) => Some(value.value()),
101 _ => None,
102 }
103 }
104
105 pub fn is_datetime(&self) -> bool {
107 self.as_datetime().is_some()
108 }
109
110 pub fn as_array(&self) -> Option<&Array> {
112 match *self {
113 Self::Array(ref value) => Some(value),
114 _ => None,
115 }
116 }
117
118 pub fn as_array_mut(&mut self) -> Option<&mut Array> {
120 match *self {
121 Self::Array(ref mut value) => Some(value),
122 _ => None,
123 }
124 }
125
126 pub fn is_array(&self) -> bool {
128 self.as_array().is_some()
129 }
130
131 pub fn as_inline_table(&self) -> Option<&InlineTable> {
133 match *self {
134 Self::InlineTable(ref value) => Some(value),
135 _ => None,
136 }
137 }
138
139 pub fn as_inline_table_mut(&mut self) -> Option<&mut InlineTable> {
141 match *self {
142 Self::InlineTable(ref mut value) => Some(value),
143 _ => None,
144 }
145 }
146
147 pub fn is_inline_table(&self) -> bool {
149 self.as_inline_table().is_some()
150 }
151}
152
153impl Value {
154 pub fn decor_mut(&mut self) -> &mut Decor {
161 match self {
162 Self::String(f) => f.decor_mut(),
163 Self::Integer(f) => f.decor_mut(),
164 Self::Float(f) => f.decor_mut(),
165 Self::Boolean(f) => f.decor_mut(),
166 Self::Datetime(f) => f.decor_mut(),
167 Self::Array(a) => a.decor_mut(),
168 Self::InlineTable(t) => t.decor_mut(),
169 }
170 }
171
172 pub fn decor(&self) -> &Decor {
179 match *self {
180 Self::String(ref f) => f.decor(),
181 Self::Integer(ref f) => f.decor(),
182 Self::Float(ref f) => f.decor(),
183 Self::Boolean(ref f) => f.decor(),
184 Self::Datetime(ref f) => f.decor(),
185 Self::Array(ref a) => a.decor(),
186 Self::InlineTable(ref t) => t.decor(),
187 }
188 }
189
190 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 pub fn span(&self) -> Option<std::ops::Range<usize>> {
214 match self {
215 Self::String(f) => f.span(),
216 Self::Integer(f) => f.span(),
217 Self::Float(f) => f.span(),
218 Self::Boolean(f) => f.span(),
219 Self::Datetime(f) => f.span(),
220 Self::Array(a) => a.span(),
221 Self::InlineTable(t) => t.span(),
222 }
223 }
224
225 pub(crate) fn despan(&mut self, input: &str) {
226 match self {
227 Self::String(f) => f.despan(input),
228 Self::Integer(f) => f.despan(input),
229 Self::Float(f) => f.despan(input),
230 Self::Boolean(f) => f.despan(input),
231 Self::Datetime(f) => f.despan(input),
232 Self::Array(a) => a.despan(input),
233 Self::InlineTable(t) => t.despan(input),
234 }
235 }
236}
237
238#[cfg(feature = "parse")]
239impl FromStr for Value {
240 type Err = crate::TomlError;
241
242 fn from_str(s: &str) -> Result<Self, Self::Err> {
244 let source = toml_parser::Source::new(s);
245 let mut sink = crate::error::TomlSink::<Option<_>>::new(source);
246 let mut value = crate::parser::parse_value(source, &mut sink);
247 if let Some(err) = sink.into_inner() {
248 Err(err)
249 } else {
250 value.decor_mut().clear();
252 value.despan(s);
253 Ok(value)
254 }
255 }
256}
257
258impl<'b> From<&'b Self> for Value {
259 fn from(s: &'b Self) -> Self {
260 s.clone()
261 }
262}
263
264impl<'b> From<&'b str> for Value {
265 fn from(s: &'b str) -> Self {
266 s.to_owned().into()
267 }
268}
269
270impl<'b> From<&'b String> for Value {
271 fn from(s: &'b String) -> Self {
272 s.to_owned().into()
273 }
274}
275
276impl From<String> for Value {
277 fn from(s: String) -> Self {
278 Self::String(Formatted::new(s))
279 }
280}
281
282impl From<i64> for Value {
283 fn from(i: i64) -> Self {
284 Self::Integer(Formatted::new(i))
285 }
286}
287
288impl From<f64> for Value {
289 fn from(f: f64) -> Self {
290 Self::Float(Formatted::new(f))
292 }
293}
294
295impl From<bool> for Value {
296 fn from(b: bool) -> Self {
297 Self::Boolean(Formatted::new(b))
298 }
299}
300
301impl From<Datetime> for Value {
302 fn from(d: Datetime) -> Self {
303 Self::Datetime(Formatted::new(d))
304 }
305}
306
307impl From<Date> for Value {
308 fn from(d: Date) -> Self {
309 let d: Datetime = d.into();
310 d.into()
311 }
312}
313
314impl From<Time> for Value {
315 fn from(d: Time) -> Self {
316 let d: Datetime = d.into();
317 d.into()
318 }
319}
320
321impl From<Array> for Value {
322 fn from(array: Array) -> Self {
323 Self::Array(array)
324 }
325}
326
327impl From<InlineTable> for Value {
328 fn from(table: InlineTable) -> Self {
329 Self::InlineTable(table)
330 }
331}
332
333impl<V: Into<Self>> FromIterator<V> for Value {
334 fn from_iter<I>(iter: I) -> Self
335 where
336 I: IntoIterator<Item = V>,
337 {
338 let array: Array = iter.into_iter().collect();
339 Self::Array(array)
340 }
341}
342
343impl<K: Into<Key>, V: Into<Self>> FromIterator<(K, V)> for Value {
344 fn from_iter<I>(iter: I) -> Self
345 where
346 I: IntoIterator<Item = (K, V)>,
347 {
348 let table: InlineTable = iter.into_iter().collect();
349 Self::InlineTable(table)
350 }
351}
352
353#[cfg(feature = "display")]
354impl std::fmt::Display for Value {
355 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
356 crate::encode::encode_value(self, f, None, ("", ""))
357 }
358}
359
360pub(crate) const DEFAULT_VALUE_DECOR: (&str, &str) = (" ", "");
362pub(crate) const DEFAULT_TRAILING_VALUE_DECOR: (&str, &str) = (" ", " ");
364pub(crate) const DEFAULT_LEADING_VALUE_DECOR: (&str, &str) = ("", "");
366
367#[cfg(test)]
368#[cfg(feature = "parse")]
369#[cfg(feature = "display")]
370mod tests {
371 use super::*;
372
373 #[test]
374 fn from_iter_formatting() {
375 let features = ["node".to_owned(), "mouth".to_owned()];
376 let features: Value = features.iter().cloned().collect();
377 assert_eq!(features.to_string(), r#"["node", "mouth"]"#);
378 }
379}
380
381#[test]
382#[cfg(feature = "parse")]
383#[cfg(feature = "display")]
384fn string_roundtrip() {
385 Value::from("hello").to_string().parse::<Value>().unwrap();
386}