1use crate::{Error, ErrorKind, Span};
7use std::{borrow::Cow, fmt};
8
9pub struct Value<'de> {
12 value: Option<ValueInner<'de>>,
13 pub span: Span,
15}
16
17impl<'de> Value<'de> {
18 #[inline]
20 pub fn new(value: ValueInner<'de>) -> Self {
21 Self::with_span(value, Span::default())
22 }
23
24 #[inline]
26 pub fn with_span(value: ValueInner<'de>, span: Span) -> Self {
27 Self {
28 value: Some(value),
29 span,
30 }
31 }
32
33 #[inline]
39 pub fn take(&mut self) -> ValueInner<'de> {
40 self.value.take().expect("the value has already been taken")
41 }
42
43 #[inline]
48 pub fn set(&mut self, value: ValueInner<'de>) {
49 self.value = Some(value);
50 }
51
52 #[inline]
54 pub fn has_keys(&self) -> bool {
55 self.value.as_ref().map_or(false, |val| {
56 if let ValueInner::Table(table) = val {
57 !table.is_empty()
58 } else {
59 false
60 }
61 })
62 }
63
64 #[inline]
66 pub fn has_key(&self, key: &str) -> bool {
67 self.value.as_ref().map_or(false, |val| {
68 if let ValueInner::Table(table) = val {
69 table.contains_key(key)
70 } else {
71 false
72 }
73 })
74 }
75
76 #[inline]
79 pub fn take_string(&mut self, msg: Option<&'static str>) -> Result<Cow<'de, str>, Error> {
80 match self.take() {
81 ValueInner::String(s) => Ok(s),
82 other => Err(Error {
83 kind: ErrorKind::Wanted {
84 expected: msg.unwrap_or("a string"),
85 found: other.type_str(),
86 },
87 span: self.span,
88 line_info: None,
89 }),
90 }
91 }
92
93 #[inline]
95 pub fn as_str(&self) -> Option<&str> {
96 self.value.as_ref().and_then(|v| v.as_str())
97 }
98
99 #[inline]
101 pub fn as_table(&self) -> Option<&Table<'de>> {
102 self.value.as_ref().and_then(|v| v.as_table())
103 }
104
105 #[inline]
107 pub fn as_array(&self) -> Option<&Array<'de>> {
108 self.value.as_ref().and_then(|v| v.as_array())
109 }
110
111 #[inline]
113 pub fn as_integer(&self) -> Option<i64> {
114 self.value.as_ref().and_then(|v| v.as_integer())
115 }
116
117 #[inline]
119 pub fn as_float(&self) -> Option<f64> {
120 self.value.as_ref().and_then(|v| v.as_float())
121 }
122
123 #[inline]
125 pub fn as_bool(&self) -> Option<bool> {
126 self.value.as_ref().and_then(|v| v.as_bool())
127 }
128
129 pub fn pointer(&self, pointer: &str) -> Option<&Self> {
148 if pointer.is_empty() {
149 return Some(self);
150 } else if !pointer.starts_with('/') {
151 return None;
152 }
153
154 pointer
155 .split('/')
156 .skip(1)
157 .try_fold(self, move |target, token| {
161 (match &target.value {
162 Some(ValueInner::Table(tab)) => tab.get(token),
163 Some(ValueInner::Array(list)) => parse_index(token).and_then(|x| list.get(x)),
164 _ => None,
165 })
166 .filter(|v| v.value.is_some())
167 })
168 }
169
170 pub fn pointer_mut(&mut self, pointer: &'de str) -> Option<&mut Self> {
172 if pointer.is_empty() {
173 return Some(self);
174 } else if !pointer.starts_with('/') {
175 return None;
176 }
177
178 pointer
179 .split('/')
180 .skip(1)
181 .try_fold(self, |target, token| {
185 (match &mut target.value {
186 Some(ValueInner::Table(tab)) => tab.get_mut(token),
187 Some(ValueInner::Array(list)) => {
188 parse_index(token).and_then(|x| list.get_mut(x))
189 }
190 _ => None,
191 })
192 .filter(|v| v.value.is_some())
193 })
194 }
195}
196
197fn parse_index(s: &str) -> Option<usize> {
198 if s.starts_with('+') || (s.starts_with('0') && s.len() != 1) {
199 return None;
200 }
201 s.parse().ok()
202}
203
204impl<'de> AsRef<ValueInner<'de>> for Value<'de> {
205 fn as_ref(&self) -> &ValueInner<'de> {
206 self.value
207 .as_ref()
208 .expect("the value has already been taken")
209 }
210}
211
212impl fmt::Debug for Value<'_> {
213 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
214 write!(f, "{:?}", self.value)
215 }
216}
217
218#[derive(Clone)]
220pub struct Key<'de> {
221 pub name: Cow<'de, str>,
224 pub span: Span,
226}
227
228impl std::borrow::Borrow<str> for Key<'_> {
229 fn borrow(&self) -> &str {
230 self.name.as_ref()
231 }
232}
233
234impl fmt::Debug for Key<'_> {
235 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
236 f.write_str(&self.name)
237 }
238}
239
240impl fmt::Display for Key<'_> {
241 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
242 f.write_str(&self.name)
243 }
244}
245
246impl Ord for Key<'_> {
247 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
248 self.name.cmp(&other.name)
249 }
250}
251
252impl PartialOrd for Key<'_> {
253 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
254 Some(self.cmp(other))
255 }
256}
257
258impl PartialEq for Key<'_> {
259 fn eq(&self, other: &Self) -> bool {
260 self.name.eq(&other.name)
261 }
262}
263
264impl Eq for Key<'_> {}
265
266pub type Table<'de> = std::collections::BTreeMap<Key<'de>, Value<'de>>;
270pub type Array<'de> = Vec<Value<'de>>;
272
273#[derive(Debug)]
278pub enum ValueInner<'de> {
279 String(Cow<'de, str>),
284 Integer(i64),
286 Float(f64),
288 Boolean(bool),
290 Array(Array<'de>),
292 Table(Table<'de>),
294}
295
296impl<'de> ValueInner<'de> {
297 pub fn type_str(&self) -> &'static str {
299 match self {
300 Self::String(..) => "string",
301 Self::Integer(..) => "integer",
302 Self::Float(..) => "float",
303 Self::Boolean(..) => "boolean",
304 Self::Array(..) => "array",
305 Self::Table(..) => "table",
306 }
307 }
308
309 #[inline]
311 pub fn as_str(&self) -> Option<&str> {
312 if let Self::String(s) = self {
313 Some(s.as_ref())
314 } else {
315 None
316 }
317 }
318
319 #[inline]
321 pub fn as_table(&self) -> Option<&Table<'de>> {
322 if let ValueInner::Table(t) = self {
323 Some(t)
324 } else {
325 None
326 }
327 }
328
329 #[inline]
331 pub fn as_array(&self) -> Option<&Array<'de>> {
332 if let ValueInner::Array(a) = self {
333 Some(a)
334 } else {
335 None
336 }
337 }
338
339 #[inline]
341 pub fn as_integer(&self) -> Option<i64> {
342 if let ValueInner::Integer(i) = self {
343 Some(*i)
344 } else {
345 None
346 }
347 }
348
349 #[inline]
351 pub fn as_float(&self) -> Option<f64> {
352 if let ValueInner::Float(f) = self {
353 Some(*f)
354 } else {
355 None
356 }
357 }
358
359 #[inline]
361 pub fn as_bool(&self) -> Option<bool> {
362 if let ValueInner::Boolean(b) = self {
363 Some(*b)
364 } else {
365 None
366 }
367 }
368}