url_cleaner_engine/glue/
json.rs

1//! Generating [`serde_json::Value`]s using [`StringSource`]s.
2
3use std::collections::HashMap;
4use std::str::FromStr;
5
6use serde::{Serialize, Deserialize};
7use serde_json::Value;
8
9use crate::types::*;
10use crate::util::*;
11
12/// Rules for making a [`serde_json::Value`] using [`StringSource`]s.
13#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Suitability)]
14#[serde(deny_unknown_fields)]
15#[serde(remote = "Self")]
16pub enum StringSourceJsonValue {
17    /// [`Value::Null`].
18    Null,
19    /// [`Value::Bool`].
20    Bool(bool),
21    /// [`Value::Number`].
22    Number(serde_json::value::Number),
23    /// [`Value::String`].
24    /// # Errors
25    /// If the call to [`StringSource::get`] returns an error, that error is returned.
26    ///
27    /// If the call to [`StringSource::get`] returns [`None`], returns the error [`StringSourceError::StringSourceIsNone`].
28    String(StringSource),
29    /// [`Value::Array`].
30    /// # Errors
31    /// If any call to [`StringSource::get`] returns an error, that error is returned.
32    Array(Vec<Self>),
33    /// [`Value::Object`].
34    /// # Errors
35    /// If any call to [`StringSource::get`] returns an error, that error is returned.
36    Object(HashMap<String, Self>)
37}
38
39impl FromStr for StringSourceJsonValue {
40    type Err = std::convert::Infallible;
41
42    /// Makes a [`Self::String`].
43    fn from_str(s: &str) -> Result<Self, Self::Err> {
44        Ok(s.into())
45    }
46}
47
48impl From<&str> for StringSourceJsonValue {
49    fn from(value: &str) -> Self {
50        value.to_string().into()
51    }
52}
53
54impl From<String> for StringSourceJsonValue {
55    fn from(value: String) -> Self {
56        Self::String(value.into())
57    }
58}
59
60#[allow(clippy::missing_errors_doc, reason = "Who cares?")]
61impl Serialize for StringSourceJsonValue {
62    fn serialize<S: serde::ser::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
63        <StringSourceJsonValue>::serialize(self, serializer)
64    }
65}
66
67#[allow(clippy::missing_errors_doc, reason = "Who cares?")]
68impl<'de> Deserialize<'de> for StringSourceJsonValue {
69    fn deserialize<D: serde::de::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
70        struct V;
71
72        impl<'de> serde::de::Visitor<'de> for V {
73            type Value = StringSourceJsonValue;
74
75            fn expecting(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
76                f.write_str("Expected all JSON values to be valid. If you're getting this error from JSON it's a bug and you should tell me.")
77            }
78
79            fn visit_str<E: serde::de::Error>(self, s: &str) -> Result<Self::Value, E> {
80                Ok(Self::Value::from(s))
81            }
82
83            fn visit_map<M: serde::de::MapAccess<'de>>(self, map: M) -> Result<Self::Value, M::Error> {
84                Self::Value::deserialize(serde::de::value::MapAccessDeserializer::new(map))
85            }
86
87            fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E> {
88                Ok(Value::Number(value.into()).into())
89            }
90
91            fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E> {
92                Ok(Value::Number(value.into()).into())
93            }
94
95            fn visit_f64<E>(self, value: f64) -> Result<Self::Value, E> {
96                Ok(serde_json::Number::from_f64(value).map_or(Value::Null, Value::Number).into())
97            }
98        }
99
100        deserializer.deserialize_any(V)
101    }
102}
103
104impl From<Value> for StringSourceJsonValue {
105    fn from(value: Value) -> Self {
106        match value {
107            Value::Null      => Self::Null,
108            Value::Bool  (x) => Self::Bool  (x),
109            Value::Number(x) => Self::Number(x),
110            Value::String(x) => Self::String(x.into()),
111            Value::Array (x) => Self::Array (x.into_iter().map(Into::into).collect()),
112            Value::Object(x) => Self::Object(x.into_iter().map(|(k, v)| (k, v.into())).collect())
113        }
114    }
115}
116
117impl StringSourceJsonValue {
118    /// Makes a [`serde_json::Value`].
119    /// # Errors
120    /// See each variant of [`Self`] for when each variant returns an error.
121    ///
122    /// But TL;DR: If any call to [`StringSource::get`] returns an error, that error is returned.
123    pub fn make(&self, task_state: &TaskStateView) -> Result<Value, StringSourceError> {
124        debug!(StringSourceJsonValue::make, self);
125
126        Ok(match self {
127            Self::Null      => Value::Null,
128            Self::Bool  (x) => Value::Bool(*x),
129            Self::Number(x) => Value::Number(x.clone()),
130            Self::String(x) => Value::String(get_string!(x, task_state, StringSourceError)),
131            Self::Array (x) => Value::Array(x.iter().map(|x| x.make(task_state)).collect::<Result<_, _>>()?),
132            Self::Object(x) => Value::Object(x.iter().map(|(k, v)| Ok::<_, StringSourceError>((k.clone(), v.make(task_state)?))).collect::<Result<_, _>>()?)
133        })
134    }
135}