dent_parse/
repr.rs

1use std::{collections::HashMap, fmt::Display};
2
3/// Value type returned by Dent.
4///
5/// Represents a value in Dent, which can be a string, integer, float, boolean,
6/// list or dictionary.
7///
8/// Values are stored as references to the original string, so they are only
9/// valid as long as the original string is valid. For values returned by parsing
10/// files, whether by `Dent::parse_file` or the `@import` function, they should
11/// be valid for the lifetime of the parser object.
12///
13/// # Accessing values
14///
15/// Values can be accessed using the `[]` operator, which takes either a string
16/// or an integer. If the value is a dictionary, the string will be used as a
17/// key. If the value is a list, the integer will be used as an index.
18///
19/// If a dictionary key or list index is not found, the value `Value::None` will
20/// be returned during immutable access.
21///
22/// During mutable access, if a dictionary key is not found, a new entry will be
23/// created with the value `Value::None`. If a list index is not found, the program
24/// will panic.
25///
26/// # Examples
27/// ```
28/// use dent_parse::{Dent, Value};
29///
30/// let parser = Dent::default();
31/// let value = parser.parse("{ foo: 1 }").unwrap();
32/// assert_eq!(value["foo"], Value::Int(1));
33/// ```
34/// ```
35/// use dent_parse::{Dent, Value};
36///
37/// let parser = Dent::default();
38/// let value = parser.parse("[ 1 2 3 ]").unwrap();
39/// assert_eq!(value[1], Value::Int(2));
40/// ```
41#[derive(Debug, PartialEq, Clone)]
42pub enum Value<'s> {
43    None,
44    Str(&'s str),
45    Int(i64),
46    Float(f64),
47    Bool(bool),
48    List(Vec<Value<'s>>),
49    Dict(HashMap<&'s str, Value<'s>>),
50}
51
52impl<'s> Value<'s> {
53    /// Returns the underlying string value, if it is one
54    pub fn as_str(&self) -> Option<&'s str> {
55        match self {
56            Value::Str(s) => Some(s),
57            _ => None,
58        }
59    }
60
61    /// Returns the underlying integer value, if it is one
62    pub fn as_int(&self) -> Option<i64> {
63        match self {
64            Value::Int(i) => Some(*i),
65            _ => None,
66        }
67    }
68
69    /// Returns the underlying float value, if it is one
70    pub fn as_float(&self) -> Option<f64> {
71        match self {
72            Value::Float(f) => Some(*f),
73            _ => None,
74        }
75    }
76
77    /// Returns the underlying boolean value, if it is one
78    pub fn as_bool(&self) -> Option<bool> {
79        match self {
80            Value::Bool(b) => Some(*b),
81            _ => None,
82        }
83    }
84
85    /// Returns the underlying list value, if it is one
86    pub fn as_list(&self) -> Option<&Vec<Value<'s>>> {
87        match self {
88            Value::List(l) => Some(l),
89            _ => None,
90        }
91    }
92
93    /// Returns the underlying dictionary value, if it is one
94    pub fn as_dict(&self) -> Option<&HashMap<&'s str, Value<'s>>> {
95        match self {
96            Value::Dict(d) => Some(d),
97            _ => None,
98        }
99    }
100
101    /// Returns true if the value is None
102    pub fn is_none(&self) -> bool {
103        matches!(self, Value::None)
104    }
105
106    /// Returns true if the value is a string
107    pub fn is_str(&self) -> bool {
108        matches!(self, Value::Str(_))
109    }
110
111    /// Returns true if the value is an integer
112    pub fn is_int(&self) -> bool {
113        matches!(self, Value::Int(_))
114    }
115
116    /// Returns true if the value is a float
117    pub fn is_float(&self) -> bool {
118        matches!(self, Value::Float(_))
119    }
120
121    /// Returns true if the value is a boolean
122    pub fn is_bool(&self) -> bool {
123        matches!(self, Value::Bool(_))
124    }
125
126    /// Returns true if the value is a list
127    pub fn is_list(&self) -> bool {
128        matches!(self, Value::List(_))
129    }
130
131    /// Returns true if the value is a dictionary
132    pub fn is_dict(&self) -> bool {
133        matches!(self, Value::Dict(_))
134    }
135
136    /// Returns the length of the value, if it is a list or dictionary
137    pub fn len(&self) -> Option<usize> {
138        match self {
139            Value::List(l) => Some(l.len()),
140            Value::Dict(d) => Some(d.len()),
141            _ => None,
142        }
143    }
144
145    /// Returns true if the value is empty, if it is a list or dictionary
146    pub fn is_empty(&self) -> bool {
147        match self {
148            Value::List(l) => l.is_empty(),
149            Value::Dict(d) => d.is_empty(),
150            _ => false,
151        }
152    }
153}
154
155impl<'i, 's> std::ops::Index<&'i str> for Value<'s> {
156    type Output = Value<'s>;
157
158    fn index(&self, key: &'i str) -> &Self::Output {
159        match self {
160            Value::Dict(d) => d.get(key).unwrap_or(&Value::None),
161            _ => &Value::None,
162        }
163    }
164}
165
166impl<'s> std::ops::IndexMut<&'s str> for Value<'s> {
167    fn index_mut(&mut self, key: &'s str) -> &mut Self::Output {
168        match self {
169            Value::Dict(d) => d.entry(key).or_insert(Value::None),
170            _ => panic!("Cannot index non-dict value"),
171        }
172    }
173}
174
175impl<'s> std::ops::Index<usize> for Value<'s> {
176    type Output = Value<'s>;
177
178    fn index(&self, key: usize) -> &Self::Output {
179        match self {
180            Value::List(l) => l.get(key).unwrap_or(&Value::None),
181            _ => &Value::None,
182        }
183    }
184}
185
186impl<'s> std::ops::IndexMut<usize> for Value<'s> {
187    fn index_mut(&mut self, key: usize) -> &mut Self::Output {
188        match self {
189            Value::List(l) => match l.get_mut(key) {
190                Some(v) => v,
191                None => panic!("Index out of bounds"),
192            },
193            _ => panic!("Cannot index non-list value"),
194        }
195    }
196}
197
198impl<'s> Display for Value<'s> {
199    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
200        match self {
201            Value::None => write!(f, "none"),
202            Value::Str(s) => write!(f, "{}", s),
203            Value::Int(i) => write!(f, "{}", i),
204            Value::Float(fl) => write!(f, "{}", fl),
205            Value::Bool(b) => write!(f, "{}", b),
206            Value::List(l) => {
207                write!(f, "[")?;
208                for v in l.iter() {
209                    write!(f, " {}", v)?;
210                }
211                write!(f, " ]")
212            }
213            Value::Dict(d) => {
214                write!(f, "{{")?;
215                for (k, v) in d.iter() {
216                    write!(f, " {}: {}", k, v)?;
217                }
218                write!(f, " }}")
219            }
220        }
221    }
222}