protoflow_blocks/blocks/io/
decode_json.rs1extern crate std;
4
5use crate::{
6 prelude::{BTreeMap, Bytes, ToString, Vec},
7 StdioConfig, StdioError, StdioSystem, System,
8};
9use protoflow_core::{
10 types::Value, Block, BlockError, BlockResult, BlockRuntime, InputPort, OutputPort,
11};
12use protoflow_derive::Block;
13use simple_mermaid::mermaid;
14use struson::reader::*;
15
16#[doc = mermaid!("../../../doc/io/decode_json.mmd")]
20#[doc = mermaid!("../../../doc/io/decode_json.seq.mmd" framed)]
23#[derive(Block, Clone)]
44pub struct DecodeJson {
45 #[input]
47 pub input: InputPort<Bytes>,
48
49 #[output]
51 pub output: OutputPort<Value>,
52}
53
54impl DecodeJson {
55 pub fn new(input: InputPort<Bytes>, output: OutputPort<Value>) -> Self {
56 Self { input, output }
57 }
58
59 pub fn with_system(system: &System) -> Self {
60 use crate::SystemBuilding;
61 Self::new(system.input(), system.output())
62 }
63}
64
65impl Block for DecodeJson {
66 fn execute(&mut self, runtime: &dyn BlockRuntime) -> BlockResult {
67 runtime.wait_for(&self.input)?;
68
69 while let Some(input) = self.input.recv()? {
70 let output = {
71 let mut json = JsonStreamReader::new(input.as_ref());
72 decode(&mut json).map_err(|e| BlockError::Other(e.to_string()))?
73 };
74 self.output.send(&output)?;
75 }
76
77 Ok(())
78 }
79}
80
81pub fn decode(json: &mut JsonStreamReader<&[u8]>) -> Result<Value, ReaderError> {
82 use protoflow_core::types::{value::Kind::*, ListValue as LV, Struct};
83
84 let kind = match json.peek()? {
85 ValueType::Null => json.next_null().map(|_| NullValue(0))?,
86 ValueType::Boolean => json.next_bool().map(BoolValue)?,
87 ValueType::Number => json.next_number_as_string().and_then(|num_str| {
88 Ok(match num_str.as_str() {
89 "NaN" => NumberValue(f64::NAN),
90 "-Infinity" => NumberValue(f64::NEG_INFINITY),
91 "Infinity" => NumberValue(f64::INFINITY),
92 number => NumberValue(number.parse::<f64>().map_err(|_| {
93 ReaderError::UnsupportedNumberValue {
94 number: number.into(),
95 location: json.current_position(false),
96 }
97 })?),
98 })
99 })?,
100 ValueType::String => json.next_string().map(StringValue)?,
101 ValueType::Array => {
102 json.begin_array()?;
103
104 let mut values = Vec::new();
105 while json.has_next().unwrap() {
106 values.push(decode(json)?);
107 }
108
109 json.end_array()?;
110 ListValue(LV { values })
111 }
112 ValueType::Object => {
113 json.begin_object()?;
114 let mut fields = BTreeMap::new();
115 while json.has_next()? {
116 let key = json.next_name_owned()?;
117 let value = decode(json)?;
118 fields.insert(key, value);
119 }
120 json.end_object()?;
121 StructValue(Struct { fields })
122 }
123 };
124
125 Ok(Value { kind: Some(kind) })
126}
127
128#[cfg(feature = "std")]
129impl StdioSystem for DecodeJson {
130 fn build_system(config: StdioConfig) -> Result<System, StdioError> {
131 config.reject_any()?;
134
135 Ok(System::build(|_s| {
136 todo!() }))
143 }
144}
145
146#[cfg(test)]
147mod tests {
148 extern crate std;
149
150 use super::{decode, DecodeJson};
151 use crate::{
152 prelude::{vec, BTreeMap, ToString},
153 System, SystemBuilding,
154 };
155
156 #[test]
157 fn instantiate_block() {
158 let _ = System::build(|s| {
160 let _ = s.block(DecodeJson::new(s.input(), s.output()));
161 });
162 }
163
164 #[test]
165 fn test_decode() {
166 use super::{JsonStreamReader, ReaderError, Value};
167
168 use protoflow_core::types::{
169 value::Kind::{self, *},
170 ListValue as LV, Struct,
171 };
172
173 fn to_value(kind: Kind) -> Value {
174 Value { kind: Some(kind) }
175 }
176
177 fn read_value(input: &str) -> Result<Value, ReaderError> {
178 let mut json = JsonStreamReader::new(input.as_ref());
179 decode(&mut json)
180 }
181
182 assert_eq!(to_value(NullValue(0)), read_value("null").unwrap());
183 assert_eq!(to_value(BoolValue(false)), read_value("false").unwrap());
184 assert_eq!(to_value(BoolValue(true)), read_value("true").unwrap());
185 assert_eq!(to_value(NumberValue(0.)), read_value("0").unwrap());
186 assert_eq!(to_value(NumberValue(1.)), read_value("1").unwrap());
187 assert_eq!(to_value(NumberValue(1.)), read_value("1").unwrap());
188 assert_eq!(to_value(NumberValue(1.)), read_value("1.0").unwrap());
189 assert_eq!(to_value(NumberValue(1.123)), read_value("1.123").unwrap());
190 assert_eq!(to_value(NumberValue(-1.123)), read_value("-1.123").unwrap());
191 assert_eq!(to_value(NumberValue(100.)), read_value("100").unwrap());
192 assert_eq!(to_value(NumberValue(1000.)), read_value("1e3").unwrap());
193
194 assert_eq!(
195 to_value(StringValue("Hello world".to_string())),
196 read_value(r#""Hello world""#).unwrap()
197 );
198
199 assert_eq!(
200 to_value(ListValue(LV { values: vec![] })),
201 read_value(r#"[]"#).unwrap()
202 );
203
204 assert_eq!(
205 to_value(ListValue(LV {
206 values: vec![
207 NullValue(0),
208 BoolValue(false),
209 BoolValue(true),
210 NumberValue(1.),
211 StringValue("foo".to_string()),
212 ListValue(LV {
213 values: vec![to_value(StringValue("nested".to_string()))]
214 }),
215 StructValue(Struct {
216 fields: {
217 let mut obj = BTreeMap::new();
218 obj.insert("foo".into(), to_value(NumberValue(1.)));
219 obj.insert("bar".into(), to_value(BoolValue(true)));
220 obj
221 }
222 }),
223 ]
224 .into_iter()
225 .map(to_value)
226 .collect()
227 })),
228 read_value(r#"[null, false, true, 1, "foo", ["nested"], {"foo": 1, "bar": true}]"#)
229 .unwrap()
230 );
231 }
232}