json_mel/
lib.rs

1#![cfg_attr(docsrs, feature(doc_cfg))]
2#![doc = include_str!("../README.md")]
3
4use melodium_core::{executive::*, *};
5use melodium_macro::{check, mel_data, mel_function, mel_package, mel_treatment};
6use std::sync::Arc;
7
8pub mod value;
9
10/// JSON data.
11///
12/// `Json` data type contains any valid json value.
13///
14/// ℹ️ The traits `ToString` and `TryToString` have different behavior for conversion:
15/// - `ToString`, as infaillible, will give the literal JSON object string;
16/// - `TryToString`, as faillible, will give the internal string _if JSON object is only a string_, and none in the other cases.
17#[mel_data(traits(ToString TryToString TryToBool TryToI64 TryToU64 TryToF64 Display))]
18#[derive(Debug, Clone, Serialize)]
19pub struct Json(pub serde_json::Value);
20
21impl ToString for Json {
22    fn to_string(&self) -> string {
23        self.0.to_string()
24    }
25}
26
27impl TryToString for Json {
28    fn try_to_string(&self) -> Option<string> {
29        if let Json(serde_json::Value::String(s)) = self {
30            Some(s.clone())
31        } else {
32            None
33        }
34    }
35}
36
37impl TryToBool for Json {
38    fn try_to_bool(&self) -> Option<bool> {
39        if let Json(serde_json::Value::Bool(b)) = self {
40            Some(*b)
41        } else {
42            None
43        }
44    }
45}
46
47impl TryToI64 for Json {
48    fn try_to_i64(&self) -> Option<i64> {
49        if let Json(serde_json::Value::Number(num)) = self {
50            num.as_i64()
51        } else {
52            None
53        }
54    }
55}
56
57impl TryToU64 for Json {
58    fn try_to_u64(&self) -> Option<u64> {
59        if let Json(serde_json::Value::Number(num)) = self {
60            num.as_u64()
61        } else {
62            None
63        }
64    }
65}
66
67impl TryToF64 for Json {
68    fn try_to_f64(&self) -> Option<f64> {
69        if let Json(serde_json::Value::Number(num)) = self {
70            num.as_f64()
71        } else {
72            None
73        }
74    }
75}
76
77impl Display for Json {
78    fn display(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
79        write!(f, "{}", serde_json::ser::to_string_pretty(&self.0).unwrap())
80    }
81}
82
83/// Parse string into Json data.
84#[mel_function]
85pub fn to_json(text: string) -> Option<Json> {
86    serde_json::from_str::<serde_json::Value>(&text)
87        .ok()
88        .map(|json| Json(json))
89}
90
91/// Parse string into Json data.
92///
93/// `json` contains json data if input `text` contains valid json, else none.
94/// `error` contains message if input `text` is not valid json, else none.
95#[mel_treatment(
96    input text Stream<string>
97    output json Stream<Option<Json>>
98    output error Stream<Option<string>>
99)]
100pub async fn to_json() {
101    'main: while let Ok(text) = text
102        .recv_many()
103        .await
104        .map(|values| TryInto::<Vec<string>>::try_into(values).unwrap())
105    {
106        for t in text {
107            let result = serde_json::from_str::<serde_json::Value>(&t);
108            match result {
109                Ok(json_value) => {
110                    if let (Err(_), Err(_)) = futures::join!(
111                        json.send_one(Some(Arc::new(Json(json_value)) as Arc<dyn Data>).into()),
112                        error.send_one(Option::<string>::None.into())
113                    ) {
114                        break 'main;
115                    }
116                }
117                Err(err) => {
118                    if let (Err(_), Err(_)) = futures::join!(
119                        json.send_one(Option::<Arc<dyn Data>>::None.into()),
120                        error.send_one(Some(err.to_string()).into())
121                    ) {
122                        break 'main;
123                    }
124                }
125            }
126        }
127    }
128}
129
130/// Validate JSON string.
131///
132/// Tells wether `text` is valid JSON or not.
133#[mel_treatment(
134    input {content(json)} text Stream<string>
135    output is_json Stream<bool>
136)]
137pub async fn validate() {
138    while let Ok(text) = text
139        .recv_many()
140        .await
141        .map(|values| TryInto::<Vec<string>>::try_into(values).unwrap())
142    {
143        check!(
144            is_json
145                .send_many(
146                    text.iter()
147                        .map(|t| match serde_json::from_str::<serde::de::IgnoredAny>(t) {
148                            Ok(_) => true,
149                            Err(_) => false,
150                        })
151                        .collect::<VecDeque<_>>()
152                        .into()
153                )
154                .await
155        );
156    }
157}
158
159mel_package!();