1use crate::shared::*;
2use crate::nonblocking::array::JsonArray;
3use crate::nonblocking::io::NonBlockingWrite;
4use crate::nonblocking::json_writer::JsonWriter;
5
6pub struct JsonObject<'a, 'b, W: NonBlockingWrite, F: JsonFormatter, FF: FloatFormat> {
17 writer: &'a mut JsonWriter<'b, W, F, FF>,
18 is_initial: bool,
19 is_ended: bool,
20}
21impl<'a, 'b, W: NonBlockingWrite, F: JsonFormatter, FF: FloatFormat> JsonObject<'a, 'b, W, F, FF> {
22 pub async fn new(writer: &'a mut JsonWriter<'b, W, F, FF>) -> Result<Self, W::Error> {
25 writer.write_bytes(b"{").await?;
26 writer.write_format_after_start_nested().await?;
27 Ok(JsonObject {
28 writer,
29 is_initial: true,
30 is_ended: false,
31 })
32 }
33
34 async fn write_key(&mut self, key: &str) -> Result<(), W::Error> {
35 if !self.is_initial {
36 self.writer.write_bytes(b",").await?;
37 self.writer.write_format_after_element().await?;
38 }
39 self.is_initial = false;
40 self.writer.write_format_indent().await?;
41 self.writer.write_escaped_string(key).await?;
42 self.writer.write_bytes(b":").await?;
43 self.writer.write_format_after_key().await
44 }
45
46 pub async fn write_string_value(&mut self, key: &str, value: &str) -> Result<(), W::Error> {
48 self.write_key(key).await?;
49 self.writer.write_escaped_string(value).await
50 }
51
52 pub async fn write_bool_value(&mut self, key: &str, value: bool) -> Result<(), W::Error> {
54 self.write_key(key).await?;
55 self.writer.write_bool(value).await
56 }
57
58 pub async fn write_null_value(&mut self, key: &str) -> Result<(), W::Error> {
60 self.write_key(key).await?;
61 self.writer.write_bytes(b"null").await
62 }
63
64 pub async fn write_f64_value(&mut self, key: &str, value: f64) -> Result<(), W::Error> {
69 self.write_key(key).await?;
70 self.writer.write_f64(value).await
71 }
72
73 pub async fn write_f32_value(&mut self, key: &str, value: f32) -> Result<(), W::Error> {
78 self.write_key(key).await?;
79 self.writer.write_f32(value).await
80 }
81
82 pub async fn start_object<'c, 'x>(&'x mut self, key: &str) -> Result<JsonObject<'c, 'b, W, F, FF>, W::Error>
87 where 'a: 'c, 'x: 'c
88 {
89 self.write_key(key).await?;
90 JsonObject::new(&mut self.writer).await
91 }
92
93 pub async fn start_array<'x, 'c>(&'x mut self, key: &str) -> Result<JsonArray<'c, 'b, W, F, FF>, W::Error>
98 where 'a: 'c, 'x: 'c
99 {
100 self.write_key(key).await?;
101 JsonArray::new(self.writer).await
102 }
103
104 pub async fn end(self) -> Result<(), W::Error> {
106 let mut mut_self = self;
107 mut_self._end().await
108 }
109
110 async fn _end(&mut self) -> Result<(), W::Error> {
111 self.writer.write_format_before_end_nested(self.is_initial).await?;
112 self.writer.write_bytes(b"}").await?;
113 self.is_ended = true;
114 Ok(())
115 }
116}
117
118macro_rules! write_obj_int {
119 ($t:ty ; $f:ident) => {
120impl<'a, 'b, W: NonBlockingWrite, F: JsonFormatter, FF: FloatFormat> JsonObject<'a, 'b, W, F, FF> {
121 pub async fn $f(&mut self, key: &str, value: $t) -> Result<(), W::Error> {
123 self.write_key(key).await?;
124 self.writer.write_raw_num(value).await
125 }
126}
127 };
128}
129write_obj_int!(i8; write_i8_value);
130write_obj_int!(u8; write_u8_value);
131write_obj_int!(i16; write_i16_value);
132write_obj_int!(u16; write_u16_value);
133write_obj_int!(i32; write_i32_value);
134write_obj_int!(u32; write_u32_value);
135write_obj_int!(i64; write_i64_value);
136write_obj_int!(u64; write_u64_value);
137write_obj_int!(i128; write_i128_value);
138write_obj_int!(u128; write_u128_value);
139write_obj_int!(isize; write_isize_value);
140write_obj_int!(usize; write_usize_value);
141
142
143
144#[cfg(test)]
145pub mod tests {
146 use super::*;
147 use crate::nonblocking::array::tests::ArrayCommand;
148 use rstest::rstest;
149 use std::io;
150
151 pub enum ObjectCommand {
152 Null(&'static str),
153 Bool(&'static str, bool),
154 String(&'static str, &'static str),
155 U8(&'static str, u8),
156 I8(&'static str, i8),
157 U16(&'static str, u16),
158 I16(&'static str, i16),
159 U32(&'static str, u32),
160 I32(&'static str, i32),
161 U64(&'static str, u64),
162 I64(&'static str, i64),
163 U128(&'static str, u128),
164 I128(&'static str, i128),
165 Usize(&'static str, usize),
166 Isize(&'static str, isize),
167 F64(&'static str, f64),
168 F32(&'static str, f32),
169 Object(&'static str, Vec<ObjectCommand>),
170 Array(&'static str, Vec<ArrayCommand>)
171 }
172 impl ObjectCommand {
173 pub async fn apply(&self, obj: &mut JsonObject<'_, '_, Vec<u8>, CompactFormatter, DefaultFloatFormat>) {
174 match self {
175 ObjectCommand::Null(key) => obj.write_null_value(key).await.unwrap(),
176 ObjectCommand::Bool(key, b) => obj.write_bool_value(key, *b).await.unwrap(),
177 ObjectCommand::String(key, s) => obj.write_string_value(key, s).await.unwrap(),
178 ObjectCommand::U8(key, n) => obj.write_u8_value(key, *n).await.unwrap(),
179 ObjectCommand::I8(key, n) => obj.write_i8_value(key, *n).await.unwrap(),
180 ObjectCommand::U16(key, n) => obj.write_u16_value(key, *n).await.unwrap(),
181 ObjectCommand::I16(key, n) => obj.write_i16_value(key, *n).await.unwrap(),
182 ObjectCommand::U32(key, n) => obj.write_u32_value(key, *n).await.unwrap(),
183 ObjectCommand::I32(key, n) => obj.write_i32_value(key, *n).await.unwrap(),
184 ObjectCommand::U64(key, n) => obj.write_u64_value(key, *n).await.unwrap(),
185 ObjectCommand::I64(key, n) => obj.write_i64_value(key, *n).await.unwrap(),
186 ObjectCommand::U128(key, n) => obj.write_u128_value(key, *n).await.unwrap(),
187 ObjectCommand::I128(key, n) => obj.write_i128_value(key, *n).await.unwrap(),
188 ObjectCommand::Usize(key, n) => obj.write_usize_value(key, *n).await.unwrap(),
189 ObjectCommand::Isize(key, n) => obj.write_isize_value(key, *n).await.unwrap(),
190 ObjectCommand::F64(key, x) => obj.write_f64_value(key, *x).await.unwrap(),
191 ObjectCommand::F32(key, x) => obj.write_f32_value(key, *x).await.unwrap(),
192 ObjectCommand::Object(key, cmds) => {
193 let mut nested = obj.start_object(key).await.unwrap();
194 for cmd in cmds {
195 Box::pin(cmd.apply(&mut nested)).await;
196 }
197 nested.end().await.unwrap();
198 }
199 ObjectCommand::Array(key, cmds) => {
200 let mut nested = obj.start_array(key).await.unwrap();
201 for cmd in cmds {
202 Box::pin(cmd.apply(&mut nested)).await;
203 }
204 nested.end().await.unwrap();
205 }
206 }
207 }
208 }
209
210 #[rstest]
211 #[case::empty(vec![], "{}")]
212 #[case::single(vec![ObjectCommand::Null("a")], r#"{"a":null}"#)]
213 #[case::two(vec![ObjectCommand::U32("a", 1), ObjectCommand::U32("b", 2)], r#"{"a":1,"b":2}"#)]
214 #[case::nested_arr(vec![ObjectCommand::Array("x", vec![])], r#"{"x":[]}"#)]
215 #[case::nested_arr_with_el(vec![ObjectCommand::Array("y", vec![ArrayCommand::U32(5)])], r#"{"y":[5]}"#)]
216 #[case::nested_arr_first(vec![ObjectCommand::Array("z", vec![]), ObjectCommand::U32("q", 4)], r#"{"z":[],"q":4}"#)]
217 #[case::nested_arr_last(vec![ObjectCommand::U32("q", 6), ObjectCommand::Array("z", vec![])], r#"{"q":6,"z":[]}"#)]
218 #[case::nested_arr_between(vec![ObjectCommand::U32("a", 7), ObjectCommand::Array("b", vec![]), ObjectCommand::U32("c", 9)], r#"{"a":7,"b":[],"c":9}"#)]
219 #[case::two_nested_arrays(vec![ObjectCommand::Array("d", vec![]), ObjectCommand::Array("e", vec![])], r#"{"d":[],"e":[]}"#)]
220 #[case::nested_obj(vec![ObjectCommand::Object("f", vec![])], r#"{"f":{}}"#)]
221 #[case::nested_obj_with_el(vec![ObjectCommand::Object("g", vec![ObjectCommand::U32("a", 3)])], r#"{"g":{"a":3}}"#)]
222 #[case::nested_obj_first(vec![ObjectCommand::Object("h", vec![]), ObjectCommand::U32("i", 0)], r#"{"h":{},"i":0}"#)]
223 #[case::nested_obj_last(vec![ObjectCommand::U32("j", 2), ObjectCommand::Object("k", vec![])], r#"{"j":2,"k":{}}"#)]
224 #[case::two_nested_objects(vec![ObjectCommand::Object("l", vec![]), ObjectCommand::Object("m", vec![])], r#"{"l":{},"m":{}}"#)]
225 #[tokio::test]
226 async fn test_object(#[case] cmds: Vec<ObjectCommand>, #[case] expected: &str) -> io::Result<()> {
227 let mut buf = Vec::new();
228 let mut writer = JsonWriter::new_compact(&mut buf);
229 {
230 let mut object_ser = JsonObject::new(&mut writer).await?;
231 for cmd in cmds {
232 cmd.apply(&mut object_ser).await;
233 }
234 object_ser.end().await?;
235 }
236
237 let actual = String::from_utf8(buf).unwrap();
238 assert_eq!(actual, expected);
239 Ok(())
240 }
241
242
243 #[rstest]
244 #[case::null(ObjectCommand::Null("a"), "null")]
245 #[case::bool_true(ObjectCommand::Bool("a", true), "true")]
246 #[case::bool_false(ObjectCommand::Bool("a", false), "false")]
247 #[case::string(ObjectCommand::String("a", "asdf"), r#""asdf""#)]
248 #[case::string_escaped(ObjectCommand::String("a", "\r\n"), r#""\r\n""#)]
249 #[case::u8(ObjectCommand::U8("a", 2u8), "2")]
250 #[case::i8(ObjectCommand::I8("a", -3i8), "-3")]
251 #[case::u16(ObjectCommand::U16("a", 4u16), "4")]
252 #[case::i16(ObjectCommand::I16("a", -5i16), "-5")]
253 #[case::u32(ObjectCommand::U32("a", 6u32), "6")]
254 #[case::i32(ObjectCommand::I32("a", -7i32), "-7")]
255 #[case::u64(ObjectCommand::U64("a", 8u64), "8")]
256 #[case::i64(ObjectCommand::I64("a", -9i64), "-9")]
257 #[case::u128(ObjectCommand::U128("a", 12u128), "12")]
258 #[case::i128(ObjectCommand::I128("a", -13i128), "-13")]
259 #[case::usize(ObjectCommand::Usize("a", 10usize), "10")]
260 #[case::isize(ObjectCommand::Isize("a", -11isize), "-11")]
261 #[case::f64(ObjectCommand::F64("a", 2.0), "2")]
262 #[case::f64_exp_5(ObjectCommand::F64("a", 1.234e5), "123400")]
263 #[case::f64_exp_10(ObjectCommand::F64("a", 1.234e10), "1.234e10")]
264 #[case::f64_exp_20(ObjectCommand::F64("a", 1.234e20), "1.234e20")]
265 #[case::f64_exp_neg_3(ObjectCommand::F64("a", 1.234e-3), "0.001234")]
266 #[case::f64_exp_neg_10(ObjectCommand::F64("a", 1.234e-10), "1.234e-10")]
267 #[case::f64_neg(ObjectCommand::F64("a", -2.0), "-2")]
268 #[case::f64_neg_exp_5(ObjectCommand::F64("a", -1.234e5), "-123400")]
269 #[case::f64_neg_exp_10(ObjectCommand::F64("a", -1.234e10), "-1.234e10")]
270 #[case::f64_neg_exp_20(ObjectCommand::F64("a", -1.234e20), "-1.234e20")]
271 #[case::f64_neg_exp_neg_3(ObjectCommand::F64("a", -1.234e-3), "-0.001234")]
272 #[case::f64_neg_exp_neg_10(ObjectCommand::F64("a", -1.234e-10), "-1.234e-10")]
273 #[case::f64_inf(ObjectCommand::F64("a", f64::INFINITY), "null")]
274 #[case::f64_neg_inf(ObjectCommand::F64("a", f64::NEG_INFINITY), "null")]
275 #[case::f64_nan(ObjectCommand::F64("a", f64::NAN), "null")]
276 #[case::f32(ObjectCommand::F32("a", 2.0), "2")]
277 #[case::f32_exp_5(ObjectCommand::F32("a", 1.234e5), "123400")]
278 #[case::f32_exp_10(ObjectCommand::F32("a", 1.234e10), "1.234e10")]
279 #[case::f32_exp_20(ObjectCommand::F32("a", 1.234e20), "1.234e20")]
280 #[case::f32_exp_neg_3(ObjectCommand::F32("a", 1.234e-3), "0.001234")]
281 #[case::f32_exp_neg_10(ObjectCommand::F32("a", 1.234e-10), "1.234e-10")]
282 #[case::f32_neg(ObjectCommand::F32("a", -2.0), "-2")]
283 #[case::f32_neg_exp_5(ObjectCommand::F32("a", -1.234e5), "-123400")]
284 #[case::f32_neg_exp_10(ObjectCommand::F32("a", -1.234e10), "-1.234e10")]
285 #[case::f32_neg_exp_20(ObjectCommand::F32("a", -1.234e20), "-1.234e20")]
286 #[case::f32_neg_exp_neg_3(ObjectCommand::F32("a", -1.234e-3), "-0.001234")]
287 #[case::f32_neg_exp_neg_10(ObjectCommand::F32("a", -1.234e-10), "-1.234e-10")]
288 #[case::f32_inf(ObjectCommand::F32("a", f32::INFINITY), "null")]
289 #[case::f32_neg_inf(ObjectCommand::F32("a", f32::NEG_INFINITY), "null")]
290 #[case::f32_nan(ObjectCommand::F32("a", f32::NAN), "null")]
291 #[tokio::test]
292 async fn test_write_value(#[case] cmd: ObjectCommand, #[case] expected: &str) -> io::Result<()> {
293 {
294 let mut buf = Vec::new();
295 let mut writer = JsonWriter::new_compact(&mut buf);
296 {
297 let mut object_ser = JsonObject::new(&mut writer).await?;
298 cmd.apply(&mut object_ser).await;
299 object_ser.end().await?;
300 }
301
302 let actual = String::from_utf8(buf).unwrap();
303 let expected = format!(r#"{}"a":{}{}"#, "{", expected, "}");
304 assert_eq!(actual, expected);
305 }
306
307 {
309 let mut buf = Vec::new();
310 let mut writer = JsonWriter::new_compact(&mut buf);
311 {
312 let mut object_ser = JsonObject::new(&mut writer).await?;
313 object_ser.write_null_value("x").await?;
314 cmd.apply(&mut object_ser).await;
315 object_ser.write_u32_value("y", 5).await?;
316 object_ser.end().await?;
317 }
318
319 let actual = String::from_utf8(buf).unwrap();
320 let expected = format!(r#"{}"x":null,"a":{},"y":5{}"#, "{", expected, "}");
321 assert_eq!(actual, expected);
322 }
323
324 Ok(())
325 }
326}