mason_rs/value/
mod.rs

1#[cfg(feature = "serde")]
2pub mod serde;
3
4use std::{
5    collections::HashMap,
6    fmt::{self, Display, Write},
7    io::{self, Read},
8    mem,
9    str::FromStr,
10};
11
12use crate::{deserialize, index::Index, peek_reader::PeekReader, serialize::write_indented_value};
13
14/// Represents any valid MASON value.
15#[derive(Debug, Clone, PartialEq)]
16pub enum Value {
17    Object(HashMap<String, Value>),
18    Array(Vec<Value>),
19    String(String),
20    ByteString(Vec<u8>),
21    Number(f64),
22    Bool(bool),
23    Null,
24}
25
26impl Default for Value {
27    fn default() -> Self {
28        Self::Null
29    }
30}
31
32impl Display for Value {
33    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
34        self.to_writer(f)
35    }
36}
37
38impl FromStr for Value {
39    type Err = io::Error;
40
41    /// Deserialize a [`Value`] from a MASON string.
42    ///
43    /// # Example
44    ///
45    /// ```
46    /// # use mason_rs::Value;
47    /// # use std::str::FromStr;
48    /// #
49    /// let data = Value::from_str("[1.0, true, null]").unwrap();
50    /// assert_eq!(data, Value::Array(vec![Value::Number(1.0), Value::Bool(true), Value::Null]))
51    ///
52    /// ```
53    ///
54    /// # Errors
55    ///
56    /// This function can fail if the string is not valid MASON.
57    fn from_str(string: &str) -> io::Result<Self> {
58        Self::from_reader(string.as_bytes())
59    }
60}
61
62impl Value {
63    /// Deserialize a [`Value`] from an I/O stream of MASON.
64    ///
65    /// The content of the I/O stream is buffered in memory using a [`std::io::BufReader`].
66    ///
67    /// It is expected that the input stream ends after the deserialized value.
68    /// If the stream does not end, such as in the case of a persistent socket connection,
69    /// this function will not return.
70    ///
71    /// # Example
72    ///
73    /// ```
74    /// # use mason_rs::Value;
75    /// # use std::str::FromStr;
76    /// #
77    /// use std::fs::File;
78    ///
79    /// fn main() {
80    /// # }
81    /// # fn fake_main() {
82    ///     let value = Value::from_reader(File::open("test.mason").unwrap()).unwrap();
83    ///     println!("{:?}", value);
84    /// }
85    /// ```
86    ///
87    /// # Errors
88    ///
89    /// This function can fail if the I/O stream is not valid MASON, or if any errors were
90    /// encountered while reading from the stream.
91    pub fn from_reader(reader: impl Read) -> io::Result<Self> {
92        let mut peek_reader = PeekReader::new(reader);
93        deserialize::parse_document(&mut peek_reader)
94    }
95
96    /// Deserialize a [`Value`] from a slice of MASON bytes.
97    ///
98    /// # Example
99    ///
100    /// ```
101    /// # use mason_rs::Value;
102    /// # use std::str::FromStr;
103    /// #
104    /// let data = Value::from_slice(b"[1.0, true, null]").unwrap();
105    /// assert_eq!(data, Value::Array(vec![Value::Number(1.0), Value::Bool(true), Value::Null]))
106    /// ```
107    ///
108    /// # Errors
109    ///
110    /// This function can fail if the byte slice is not valid MASON.
111    pub fn from_slice(bytes: &[u8]) -> io::Result<Self> {
112        Self::from_reader(bytes)
113    }
114
115    /// Serialize a [`Value`] using the given writer.
116    ///
117    /// # Example
118    ///
119    /// ```
120    /// # use mason_rs::Value;
121    /// # use std::str::FromStr;
122    /// #
123    /// let value_string = r#"vec: [1, true, false, null]"#;
124    /// let value = Value::from_str(value_string).unwrap();
125    ///
126    /// let mut writer = String::new();
127    /// Value::to_writer(&value, &mut writer);
128    /// assert_eq!(writer, value_string);
129    /// ```
130    ///
131    /// This is also the function used by `Value`'s display implementation:
132    ///
133    /// ```
134    /// # use mason_rs::Value;
135    /// # use std::str::FromStr;
136    /// #
137    /// let value_string = r#""some bytes": b"This \b \x0e\t is \x7f bytes!""#;
138    /// let value = Value::from_str(value_string).unwrap();
139    ///
140    /// assert_eq!(value.to_string(), value_string);
141    /// ```
142    pub fn to_writer<W: Write>(&self, writer: &mut W) -> fmt::Result {
143        write_indented_value(self, writer, "    ", 0)
144    }
145
146    /// Return a string description of the `Value`.
147    ///
148    /// ```
149    /// # use mason_rs::Value;
150    /// # use std::str::FromStr;
151    /// #
152    /// let value = Value::from_str(r#"{a: 2, b: false}"#).unwrap();
153    /// assert_eq!(value.value_type(), "object");
154    /// assert_eq!(value["a"].value_type(), "number");
155    /// assert_eq!(value["b"].value_type(), "boolean");
156    /// ```
157    pub fn value_type(&self) -> &'static str {
158        match self {
159            Self::Null => "null",
160            Self::Bool(_) => "boolean",
161            Self::Number(_) => "number",
162            Self::String(_) => "string",
163            Self::ByteString(_) => "byte string",
164            Self::Array(_) => "array",
165            Self::Object(_) => "object",
166        }
167    }
168
169    /// Index into a MASON array or object. A string index can be used to access a
170    /// value in an object, and a usize index can be used to access an element of an
171    /// array.
172    ///
173    /// Returns `None` if the type of `self` does not match the type of the
174    /// index, for example if the index is a string and `self` is an array or a
175    /// number. Also returns `None` if the given key does not exist in the object
176    /// or the given index is not within the bounds of the array.
177    ///
178    /// ```
179    /// # use mason_rs::Value;
180    /// # use std::str::FromStr;
181    /// #
182    /// let object = Value::from_str(r#"{ "A": 65, "B": 66, "C": 67 }"#).unwrap();
183    /// assert_eq!(*object.get("A").unwrap(), Value::Number(65.0));
184    ///
185    /// let array = Value::from_str(r#"[ "A", "B", "C" ]"#).unwrap();
186    /// assert_eq!(*array.get(2).unwrap(), Value::String("C".into()));
187    ///
188    /// assert_eq!(array.get("A"), None);
189    /// ```
190    ///
191    /// Square brackets can also be used to index into a value in a more concise
192    /// way. This returns `Value::Null` in cases where `get` would have returned
193    /// `None`.
194    ///
195    /// ```
196    /// # use mason_rs::Value;
197    /// # use std::str::FromStr;
198    /// #
199    /// let object = Value::from_str(r#"{
200    ///     "A": ["a", "á", "à"],
201    ///     "B": ["b", "b́"],
202    ///     "C": ["c", "ć", "ć̣", "ḉ"],
203    /// }"#).unwrap();
204    /// assert_eq!(object["B"][0], Value::String("b".into()));
205    ///
206    /// assert_eq!(object["D"], Value::Null);
207    /// assert_eq!(object[0]["x"]["y"]["z"], Value::Null);
208    /// ```
209    pub fn get<I: Index>(&self, index: I) -> Option<&Self> {
210        index.index_into(self)
211    }
212
213    /// Mutably index into a MASON array or object. A string index can be used to
214    /// access a value in an object, and a usize index can be used to access an
215    /// element of an array.
216    ///
217    /// Returns `None` if the type of `self` does not match the type of the
218    /// index, for example if the index is a string and `self` is an array or a
219    /// number. Also returns `None` if the given key does not exist in the object
220    /// or the given index is not within the bounds of the array.
221    ///
222    /// ```
223    /// # use mason_rs::Value;
224    /// # use std::str::FromStr;
225    /// #
226    /// let mut object = Value::from_str(r#"{ "A": 65, "B": 66, "C": 67 }"#).unwrap();
227    /// *object.get_mut("A").unwrap() = Value::Number(69.0);
228    ///
229    /// let mut array = Value::from_str(r#"[ "A", "B", "C" ]"#).unwrap();
230    /// *array.get_mut(2).unwrap() = Value::String("D".into());
231    /// ```
232    pub fn get_mut<I: Index>(&mut self, index: I) -> Option<&mut Self> {
233        index.index_into_mut(self)
234    }
235
236    /// Returns true if the `Value` is an Object. Returns false otherwise.
237    ///
238    /// For any Value on which `is_object` returns true, `as_object` and
239    /// `as_object_mut` are guaranteed to return the hashmap representing the object.
240    ///
241    /// ```
242    /// # use mason_rs::Value;
243    /// # use std::str::FromStr;
244    /// #
245    /// let obj = Value::from_str(r#"{ "a": { "nested": true }, "b": ["an", "array"] }"#).unwrap();
246    ///
247    /// assert!(obj.is_object());
248    /// assert!(obj["a"].is_object());
249    ///
250    /// // array, not an object
251    /// assert!(!obj["b"].is_object());
252    /// ```
253    pub fn is_object(&self) -> bool {
254        self.as_object().is_some()
255    }
256
257    /// If the `Value` is an Object, returns the associated object. Returns None
258    /// otherwise.
259    ///
260    /// ```
261    /// # use mason_rs::Value;
262    /// # use std::str::FromStr;
263    /// #
264    /// let v = Value::from_str(r#"{ "a": { "nested": true }, "b": ["an", "array"] }"#).unwrap();
265    ///
266    /// // The length of `{"nested": true}` is 1 entry.
267    /// assert_eq!(v["a"].as_object().unwrap().len(), 1);
268    ///
269    /// // The array `["an", "array"]` is not an object.
270    /// assert_eq!(v["b"].as_object(), None);
271    /// ```
272    pub fn as_object(&self) -> Option<&HashMap<String, Self>> {
273        match self {
274            Self::Object(map) => Some(map),
275            _ => None,
276        }
277    }
278
279    /// If the `Value` is an Object, returns the associated mutable object.
280    /// Returns None otherwise.
281    ///
282    /// ```
283    /// # use mason_rs::Value;
284    /// # use std::str::FromStr;
285    /// #
286    /// let mut v = Value::from_str(r#"{ "a": { "nested": true } }"#).unwrap();
287    ///
288    /// v["a"].as_object_mut().unwrap().clear();
289    /// assert_eq!(v, Value::from_str(r#"{ "a": {} }"#).unwrap());
290    /// ```
291    pub fn as_object_mut(&mut self) -> Option<&mut HashMap<String, Self>> {
292        match self {
293            Self::Object(map) => Some(map),
294            _ => None,
295        }
296    }
297
298    /// Returns true if the `Value` is an Array. Returns false otherwise.
299    ///
300    /// For any Value on which `is_array` returns true, `as_array` and
301    /// `as_array_mut` are guaranteed to return the vector representing the
302    /// array.
303    ///
304    /// ```
305    /// # use mason_rs::Value;
306    /// # use std::str::FromStr;
307    /// #
308    /// let obj = Value::from_str(r#"{ "a": ["an", "array"], "b": { "an": "object" } }"#).unwrap();
309    ///
310    /// assert!(obj["a"].is_array());
311    ///
312    /// // an object, not an array
313    /// assert!(!obj["b"].is_array());
314    /// ```
315    pub fn is_array(&self) -> bool {
316        self.as_array().is_some()
317    }
318
319    /// If the `Value` is an Array, returns the associated vector. Returns None
320    /// otherwise.
321    ///
322    /// ```
323    /// # use mason_rs::Value;
324    /// # use std::str::FromStr;
325    /// #
326    /// let v = Value::from_str(r#"{ "a": ["an", "array"], "b": { "an": "object" } }"#).unwrap();
327    ///
328    /// // The length of `["an", "array"]` is 2 elements.
329    /// assert_eq!(v["a"].as_array().unwrap().len(), 2);
330    ///
331    /// // The object `{"an": "object"}` is not an array.
332    /// assert_eq!(v["b"].as_array(), None);
333    /// ```
334    pub fn as_array(&self) -> Option<&Vec<Self>> {
335        match self {
336            Self::Array(array) => Some(array),
337            _ => None,
338        }
339    }
340
341    /// If the `Value` is an Array, returns the associated mutable vector.
342    /// Returns None otherwise.
343    ///
344    /// ```
345    /// # use mason_rs::Value;
346    /// # use std::str::FromStr;
347    /// #
348    /// let mut v = Value::from_str(r#"{ "a": ["an", "array"] }"#).unwrap();
349    ///
350    /// v["a"].as_array_mut().unwrap().clear();
351    /// assert_eq!(v, Value::from_str(r#"{ "a": [] }"#).unwrap());
352    /// ```
353    pub fn as_array_mut(&mut self) -> Option<&mut Vec<Self>> {
354        match self {
355            Self::Array(list) => Some(list),
356            _ => None,
357        }
358    }
359
360    /// Returns true if the `Value` is a String. Returns false otherwise.
361    ///
362    /// For any Value on which `is_string` returns true, `as_str` is guaranteed
363    /// to return the string slice.
364    ///
365    /// ```
366    /// # use mason_rs::Value;
367    /// # use std::str::FromStr;
368    /// #
369    /// let v = Value::from_str(r#"{ "a": "some string", "b": false }"#).unwrap();
370    ///
371    /// assert!(v["a"].is_string());
372    ///
373    /// // The boolean `false` is not a string.
374    /// assert!(!v["b"].is_string());
375    /// ```
376    pub fn is_string(&self) -> bool {
377        self.as_str().is_some()
378    }
379
380    /// If the `Value` is a String, returns the associated str. Returns None
381    /// otherwise.
382    ///
383    /// ```
384    /// # use mason_rs::Value;
385    /// # use std::str::FromStr;
386    /// #
387    /// let v = Value::from_str(r#"{ "a": "some string", "b": false }"#).unwrap();
388    ///
389    /// assert_eq!(v["a"].as_str(), Some("some string"));
390    ///
391    /// // The boolean `false` is not a string.
392    /// assert_eq!(v["b"].as_str(), None);
393    /// ```
394    pub fn as_str(&self) -> Option<&str> {
395        match self {
396            Self::String(s) => Some(s),
397            _ => None,
398        }
399    }
400
401    /// Returns true if the `Value` is a Number. Returns false otherwise.
402    ///
403    /// ```
404    /// # use mason_rs::Value;
405    /// # use std::str::FromStr;
406    /// #
407    /// let v = Value::from_str(r#"{ "a": 1, "b": "2" }"#).unwrap();
408    ///
409    /// assert!(v["a"].is_number());
410    ///
411    /// // The string `"2"` is a string, not a number.
412    /// assert!(!v["b"].is_number());
413    /// ```
414    pub fn is_number(&self) -> bool {
415        self.as_number().is_some()
416    }
417
418    /// If the `Value` is a Number, returns the associated double. Returns
419    /// None otherwise.
420    ///
421    /// ```
422    /// # use mason_rs::Value;
423    /// # use std::str::FromStr;
424    /// #
425    /// let v = Value::from_str(r#"{ "a": 1, "b": "2" }"#).unwrap();
426    ///
427    /// assert_eq!(v["a"].as_number(), Some(&1.0));
428    ///
429    /// // The string `"2"` is not a number.
430    /// assert_eq!(v["d"].as_number(), None);
431    /// ```
432    pub fn as_number(&self) -> Option<&f64> {
433        match self {
434            Self::Number(number) => Some(number),
435            _ => None,
436        }
437    }
438
439    /// Returns true if the `Value` is a Boolean. Returns false otherwise.
440    ///
441    /// For any Value on which `is_boolean` returns true, `as_bool` is
442    /// guaranteed to return the boolean value.
443    ///
444    /// ```
445    /// # use mason_rs::Value;
446    /// # use std::str::FromStr;
447    /// #
448    /// let v = Value::from_str(r#"{ "a": false, "b": "false" }"#).unwrap();
449    ///
450    /// assert!(v["a"].is_boolean());
451    ///
452    /// // The string `"false"` is a string, not a boolean.
453    /// assert!(!v["b"].is_boolean());
454    /// ```
455    pub fn is_boolean(&self) -> bool {
456        self.as_bool().is_some()
457    }
458
459    /// If the `Value` is a Boolean, returns the associated bool. Returns None
460    /// otherwise.
461    ///
462    /// ```
463    /// # use mason_rs::Value;
464    /// # use std::str::FromStr;
465    /// #
466    /// let v = Value::from_str(r#"{ "a": false, "b": "false" }"#).unwrap();
467    ///
468    /// assert_eq!(v["a"].as_bool(), Some(false));
469    ///
470    /// // The string `"false"` is a string, not a boolean.
471    /// assert_eq!(v["b"].as_bool(), None);
472    /// ```
473    pub fn as_bool(&self) -> Option<bool> {
474        match *self {
475            Self::Bool(b) => Some(b),
476            _ => None,
477        }
478    }
479
480    /// Returns true if the `Value` is a Null. Returns false otherwise.
481    ///
482    /// For any Value on which `is_null` returns true, `as_null` is guaranteed
483    /// to return `Some(())`.
484    ///
485    /// ```
486    /// # use mason_rs::Value;
487    /// # use std::str::FromStr;
488    /// #
489    /// let v = Value::from_str(r#"{ "a": null, "b": false }"#).unwrap();
490    ///
491    /// assert!(v["a"].is_null());
492    ///
493    /// // The boolean `false` is not null.
494    /// assert!(!v["b"].is_null());
495    /// ```
496    pub fn is_null(&self) -> bool {
497        self.as_null().is_some()
498    }
499
500    /// If the `Value` is a Null, returns (). Returns None otherwise.
501    ///
502    /// ```
503    /// # use mason_rs::Value;
504    /// # use std::str::FromStr;
505    /// #
506    /// let v = Value::from_str(r#"{ "a": null, "b": false }"#).unwrap();
507    ///
508    /// assert_eq!(v["a"].as_null(), Some(()));
509    ///
510    /// // The boolean `false` is not null.
511    /// assert_eq!(v["b"].as_null(), None);
512    /// ```
513    pub fn as_null(&self) -> Option<()> {
514        match *self {
515            Self::Null => Some(()),
516            _ => None,
517        }
518    }
519
520    /// Takes the value out of the `Value`, leaving a `Null` in its place.
521    ///
522    /// ```
523    /// # use mason_rs::Value;
524    /// # use std::str::FromStr;
525    /// #
526    /// let mut v = Value::from_str(r#"{ "x": "y" }"#).unwrap();
527    /// assert_eq!(v["x"].take(), Value::String("y".into()));
528    /// assert_eq!(v, Value::from_str(r#"{ "x": null }"#).unwrap());
529    /// ```
530    pub fn take(&mut self) -> Self {
531        mem::replace(self, Self::Null)
532    }
533}