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}