feattle_core/
json_reading.rs

1//! Helper free functions to read Rust values from `serde_json::Value`
2
3use crate::Error;
4use serde_json::{Map, Value};
5
6/// Indicate an error that occurred while trying to read a feattle value from JSON
7#[derive(thiserror::Error, Debug)]
8pub enum FromJsonError {
9    #[error("wrong JSON kind, got {actual} and was expecting {expected}")]
10    WrongKind {
11        expected: &'static str,
12        actual: &'static str,
13    },
14    #[error("failed to parse")]
15    ParseError {
16        cause: Box<dyn Error + Send + Sync + 'static>,
17    },
18}
19
20impl FromJsonError {
21    /// Create a new [`FromJsonError::ParseError`] variant
22    pub fn parsing<E: Error + Send + Sync + 'static>(error: E) -> FromJsonError {
23        FromJsonError::ParseError {
24            cause: Box::new(error),
25        }
26    }
27}
28
29fn json_kind(value: &Value) -> &'static str {
30    match value {
31        Value::Null => "Null",
32        Value::Bool(_) => "Bool",
33        Value::Number(_) => "Number",
34        Value::String(_) => "String",
35        Value::Array(_) => "Array",
36        Value::Object(_) => "Object",
37    }
38}
39
40macro_rules! impl_extract_json {
41    ($fn_name:ident, $output:ty, $method:ident, $expected:expr) => {
42        #[doc = "Try to read as"]
43        #[doc = $expected]
44        pub fn $fn_name(value: &Value) -> Result<$output, FromJsonError> {
45            value.$method().ok_or_else(|| FromJsonError::WrongKind {
46                expected: $expected,
47                actual: json_kind(value),
48            })
49        }
50    };
51}
52
53impl_extract_json! { extract_array, &Vec<Value>, as_array, "Array" }
54impl_extract_json! { extract_bool, bool, as_bool, "Bool" }
55impl_extract_json! { extract_f64, f64, as_f64, "Number::f64" }
56impl_extract_json! { extract_i64, i64, as_i64, "Number::i64" }
57impl_extract_json! { extract_null, (), as_null, "Null" }
58impl_extract_json! { extract_object, &Map<String, Value>, as_object, "Object" }
59impl_extract_json! { extract_str, &str, as_str, "String" }
60impl_extract_json! { extract_u64, u64, as_u64, "Number::u64" }