1use bytes::{Buf, BufMut};
2use core::marker::PhantomData;
3use rama_error::{BoxError, ErrorContext as _};
4use serde::{Serialize, de::DeserializeOwned};
5
6use super::engine::NdjsonEngine;
7use crate::{bytes::BytesMut, stream::json::ParseConfig};
8
9pub struct JsonEncoder<T> {
11 written: bool,
12 _phantom: PhantomData<fn() -> T>,
13}
14
15impl<T> JsonEncoder<T> {
16 #[must_use]
17 pub fn new() -> Self {
18 Self {
19 written: false,
20 _phantom: PhantomData,
21 }
22 }
23}
24
25impl<T> JsonEncoder<T> {
26 #[must_use]
27 pub fn new_continued() -> Self {
32 Self {
33 written: true,
34 _phantom: PhantomData,
35 }
36 }
37}
38
39impl<T> Clone for JsonEncoder<T> {
40 fn clone(&self) -> Self {
41 *self
42 }
43}
44
45impl<T> Copy for JsonEncoder<T> {}
46
47impl<T> Default for JsonEncoder<T> {
48 #[inline]
49 fn default() -> Self {
50 Self::new()
51 }
52}
53
54impl<T: Serialize> crate::stream::codec::Encoder<T> for JsonEncoder<T> {
55 type Error = BoxError;
56
57 fn encode(&mut self, data: T, buf: &mut BytesMut) -> Result<(), Self::Error> {
58 if self.written {
59 buf.put_u8(b'\n');
60 }
61 let result = serde_json::to_writer(buf.writer(), &data)
62 .context("serde-json write data to buffer")
63 .into_box_error();
64 self.written = true;
65 result
66 }
67}
68
69pub struct JsonDecoder<T> {
72 engine: NdjsonEngine<T>,
73}
74
75impl<T> JsonDecoder<T> {
76 #[must_use]
78 pub fn new() -> Self {
79 Self {
80 engine: NdjsonEngine::new(),
81 }
82 }
83
84 #[must_use]
89 pub fn new_with_config(config: ParseConfig) -> Self {
90 Self {
91 engine: NdjsonEngine::with_config(config),
92 }
93 }
94}
95
96impl<T> Default for JsonDecoder<T> {
97 fn default() -> Self {
98 Self::new()
99 }
100}
101
102impl<T: DeserializeOwned> crate::stream::codec::Decoder for JsonDecoder<T> {
103 type Item = T;
104 type Error = BoxError;
105
106 fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
107 if let Some(result) = self.engine.pop() {
109 return Ok(Some(result.context("json-deserialize next value")?));
110 }
111
112 if !src.is_empty() {
114 self.engine.input(&src);
115 src.advance(src.len());
116 }
117
118 match self.engine.pop() {
119 Some(result) => Ok(Some(result.context("json-deserialize next value")?)),
120 None => Ok(None),
121 }
122 }
123
124 fn decode_eof(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
126 if !src.is_empty() {
127 self.engine.input(&src);
128 src.advance(src.len());
129 }
130 self.engine.finalize();
131
132 if let Some(result) = self.engine.pop() {
133 return Ok(Some(result.context("json-deserialize next value")?));
134 }
135 Ok(None)
136 }
137}
138#[cfg(test)]
139mod tests {
140 use ahash::{HashSet, HashSetExt as _};
141
142 use super::*;
143 use crate::stream::codec::{Decoder as _, Encoder as _};
144 use serde::{Deserialize, Serialize};
145
146 #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
147 struct Item {
148 id: u32,
149 name: String,
150 }
151
152 #[test]
153 fn encode_single_value_no_leading_newline() -> Result<(), BoxError> {
154 let mut enc: JsonEncoder<u32> = JsonEncoder::new();
155 let mut buf = BytesMut::new();
156
157 enc.encode(42, &mut buf)?;
158
159 let s = core::str::from_utf8(&buf)?;
160 assert_eq!(s, "42"); Ok(())
162 }
163
164 #[test]
165 fn encode_multiple_values_separated_by_newline_without_trailing_newline() -> Result<(), BoxError>
166 {
167 let mut enc: JsonEncoder<u32> = JsonEncoder::new();
168 let mut buf = BytesMut::new();
169
170 enc.encode(1, &mut buf)?;
171 enc.encode(2, &mut buf)?;
172 enc.encode(3, &mut buf)?;
173
174 let bytes = buf.as_ref();
175 assert_eq!(bytes, b"1\n2\n3");
177 assert_ne!(bytes.last().copied(), Some(b'\n'));
178 Ok(())
179 }
180
181 #[test]
182 fn roundtrip_structs_encode_then_decode_all() -> Result<(), BoxError> {
183 let mut enc: JsonEncoder<Item> = JsonEncoder::new();
184 let mut buf = BytesMut::new();
185
186 let input = vec![
187 Item {
188 id: 1,
189 name: "alice".to_owned(),
190 },
191 Item {
192 id: 2,
193 name: "bob".to_owned(),
194 },
195 Item {
196 id: 3,
197 name: "carol".to_owned(),
198 },
199 ];
200
201 for it in &input {
202 enc.encode(it.clone(), &mut buf)?;
203 }
204
205 let mut dec: JsonDecoder<Item> = JsonDecoder::new();
206 let mut out = Vec::new();
207
208 if let Some(first) = dec.decode(&mut buf)? {
210 out.push(first);
211 }
212
213 while let Some(next) = dec.decode(&mut buf)? {
215 out.push(next);
216 }
217
218 if let Some(next) = dec.decode_eof(&mut buf)? {
219 out.push(next);
220 }
221
222 assert_eq!(out, input);
223 Ok(())
224 }
225
226 #[test]
227 fn decode_incremental_streaming_chunks() -> Result<(), BoxError> {
228 let mut enc: JsonEncoder<Item> = JsonEncoder::new();
230 let mut full = BytesMut::new();
231
232 let items = vec![
233 Item {
234 id: 10,
235 name: "ten".into(),
236 },
237 Item {
238 id: 20,
239 name: "twenty".into(),
240 },
241 Item {
242 id: 30,
243 name: "thirty".into(),
244 },
245 ];
246 for it in &items {
247 enc.encode(it.clone(), &mut full)?;
248 }
249
250 let all_bytes = full.freeze();
252 let split_points = [1, 7, 13, all_bytes.len()]; let mut chunks = Vec::new();
254 let mut start = 0;
255 for &end in &split_points {
256 chunks.push(all_bytes.slice(start..end));
257 start = end;
258 }
259
260 let mut dec: JsonDecoder<Item> = JsonDecoder::new();
262 let mut collected = Vec::new();
263 let mut staging = BytesMut::new();
264
265 for chunk in chunks {
266 staging.extend_from_slice(&chunk);
267 while let Some(item) = dec.decode(&mut staging)? {
269 collected.push(item);
270 }
271 }
272
273 if let Ok(Some(next)) = dec.decode_eof(&mut staging) {
274 collected.push(next);
275 }
276
277 assert_eq!(collected, items);
278 Ok(())
279 }
280
281 #[test]
282 fn decode_reports_error_for_malformed_json_line() {
283 let mut dec: JsonDecoder<serde_json::Value> = JsonDecoder::new();
284 let mut buf = BytesMut::from(&b"{not valid json}\n{\"ok\": true}\n"[..]);
285
286 let err = dec
288 .decode(&mut buf)
289 .expect_err("expected an error for malformed json");
290 let msg = format!("{err}");
291 assert!(msg.contains("json-deserialize next value"));
293
294 let next = dec
297 .decode(&mut buf)
298 .expect("second decode should not error");
299 if let Some(val) = next {
302 assert_eq!(val, serde_json::json!({"ok": true}));
303 }
304 }
305
306 #[derive(Debug, Clone, Deserialize)]
307 #[expect(dead_code)]
308 struct OrderEvent {
309 item: String,
310 quantity: u32,
311 prepaid: bool,
312 }
313
314 #[test]
315 fn decode_order_events() {
316 let inputs = [
317 r#"{"item":"Apple Watch Series 9","quantity":2,"prepaid":true}"#,
318 concat!("\n", r#"{"item":"extra item","quantity":0,"prepaid":true}"#),
319 concat!(
320 "\n",
321 r#"{"item":"Gaming Mousepad XL","quantity":1,"prepaid":false}"#
322 ),
323 concat!(
324 "\n",
325 r#"{"item":"Noise Cancelling Headphones","quantity":3,"prepaid":true}"#
326 ),
327 concat!(
328 "\n",
329 r#"{"item":"Ergonomic Chair","quantity":1,"prepaid":true}"#
330 ),
331 concat!(
332 "\n",
333 r#"{"item":"extra item","quantity":6,"prepaid":false}"#
334 ),
335 concat!(
336 "\n",
337 r#"{"item":"LED Monitor 27\"","quantity":4,"prepaid":false}"#
338 ),
339 concat!(
340 "\n",
341 r#"{"item":"Smartphone Stand","quantity":6,"prepaid":false}"#
342 ),
343 concat!(
344 "\n",
345 r#"{"item":"Mechanical Keyboard","quantity":2,"prepaid":true}"#
346 ),
347 concat!(
348 "\n",
349 r#"{"item":"extra item","quantity":12,"prepaid":true}"#
350 ),
351 concat!(
352 "\n",
353 r#"{"item":"Laptop Sleeve 15.6\"","quantity":3,"prepaid":false}"#
354 ),
355 concat!(
356 "\n",
357 r#"{"item":"USB-C Docking Station","quantity":1,"prepaid":true}"#
358 ),
359 concat!(
360 "\n",
361 r#"{"item":"Wireless Presenter","quantity":1,"prepaid":false}"#
362 ),
363 concat!(
364 "\n",
365 r#"{"item":"extra item","quantity":18,"prepaid":false}"#
366 ),
367 concat!(
368 "\n",
369 r#"{"item":"Foldable Desk Lamp","quantity":5,"prepaid":true}"#
370 ),
371 concat!(
372 "\n",
373 r#"{"item":"Portable SSD 1TB","quantity":2,"prepaid":true}"#
374 ),
375 concat!(
376 "\n",
377 r#"{"item":"Webcam Cover Slide","quantity":10,"prepaid":false}"#
378 ),
379 concat!(
380 "\n",
381 r#"{"item":"extra item","quantity":24,"prepaid":true}"#
382 ),
383 concat!(
384 "\n",
385 r#"{"item":"Bluetooth Speaker","quantity":2,"prepaid":false}"#
386 ),
387 concat!(
388 "\n",
389 r#"{"item":"Fitness Tracker Band","quantity":4,"prepaid":true}"#
390 ),
391 concat!(
392 "\n",
393 r#"{"item":"Laser Pointer","quantity":1,"prepaid":false}"#
394 ),
395 concat!(
396 "\n",
397 r#"{"item":"extra item","quantity":30,"prepaid":false}"#
398 ),
399 concat!(
400 "\n",
401 r#"{"item":"Conference Mic","quantity":2,"prepaid":true}"#
402 ),
403 concat!(
404 "\n",
405 r#"{"item":"Noise-Absorbing Panels","quantity":12,"prepaid":false}"#
406 ),
407 concat!(
408 "\n",
409 r#"{"item":"Desk Organizer Set","quantity":1,"prepaid":true}"#
410 ),
411 concat!(
412 "\n",
413 r#"{"item":"extra item","quantity":36,"prepaid":true}"#
414 ),
415 concat!(
416 "\n",
417 r#"{"item":"Whiteboard Eraser Pack","quantity":6,"prepaid":false}"#
418 ),
419 concat!(
420 "\n",
421 r#"{"item":"Travel Power Adapter","quantity":2,"prepaid":true}"#
422 ),
423 ];
424
425 let mut event_count = 0;
426 let mut unique_events = HashSet::new();
427 let mut dec: JsonDecoder<OrderEvent> = JsonDecoder::new();
428
429 for input in inputs {
430 let mut buf = BytesMut::from(input);
431 while !buf.is_empty() {
432 if let Some(event) = dec.decode(&mut buf).unwrap() {
433 unique_events.insert(event.item);
434 event_count += 1;
435 }
436 }
437 }
438 while let Some(event) = dec.decode_eof(&mut Default::default()).unwrap() {
439 unique_events.insert(event.item);
440 event_count += 1;
441 }
442 assert_eq!(28, event_count);
443 assert_eq!(22, unique_events.len());
444 }
445
446 #[test]
447 fn decode_order_events_random_chunks() {
448 let raw_input = [
449 r##"{"item":"Apple Watch Series 9","quantity":2,"prepaid":true}"##,
450 r##"{"item":"extra item","quantity":0,"prepaid":true}"##,
451 r##"{"item":"Gaming Mousepad XL","quantity":1,"prepaid":false}"##,
452 r##"{"item":"Noise Cancelling Headphones","quantity":3,"prepaid":true}"##,
453 r##"{"item":"Ergonomic Chair","quantity":1,"prepaid":true}"##,
454 r##"{"item":"extra item","quantity":6,"prepaid":false}"##,
455 r##"{"item":"LED Monitor 27\"","quantity":4,"prepaid":false}"##,
456 r##"{"item":"Smartphone Stand","quantity":6,"prepaid":false}"##,
457 r##"{"item":"Mechanical Keyboard","quantity":2,"prepaid":true}"##,
458 r##"{"item":"extra item","quantity":12,"prepaid":true}"##,
459 r##"{"item":"Laptop Sleeve 15.6\"","quantity":3,"prepaid":false}"##,
460 r##"{"item":"USB-C Docking Station","quantity":1,"prepaid":true}"##,
461 r##"{"item":"Wireless Presenter","quantity":1,"prepaid":false}"##,
462 r##"{"item":"extra item","quantity":18,"prepaid":false}"##,
463 r##"{"item":"Foldable Desk Lamp","quantity":5,"prepaid":true}"##,
464 r##"{"item":"Portable SSD 1TB","quantity":2,"prepaid":true}"##,
465 r##"{"item":"Webcam Cover Slide","quantity":10,"prepaid":false}"##,
466 r##"{"item":"extra item","quantity":24,"prepaid":true}"##,
467 r##"{"item":"Bluetooth Speaker","quantity":2,"prepaid":false}"##,
468 r##"{"item":"Fitness Tracker Band","quantity":4,"prepaid":true}"##,
469 r##"{"item":"Laser Pointer","quantity":1,"prepaid":false}"##,
470 r##"{"item":"extra item","quantity":30,"prepaid":false}"##,
471 r##"{"item":"Conference Mic","quantity":2,"prepaid":true}"##,
472 r##"{"item":"Noise-Absorbing Panels","quantity":12,"prepaid":false}"##,
473 r##"{"item":"Desk Organizer Set","quantity":1,"prepaid":true}"##,
474 r##"{"item":"extra item","quantity":36,"prepaid":true}"##,
475 r##"{"item":"Whiteboard Eraser Pack","quantity":6,"prepaid":false}"##,
476 r##"{"item":"Travel Power Adapter","quantity":2,"prepaid":true}"##,
477 ]
478 .join("\n");
479
480 for _ in 0..32 {
482 let max = raw_input.len();
483 let mut begin = 0;
484
485 let mut event_count = 0;
486 let mut unique_events = HashSet::new();
487 let mut dec: JsonDecoder<OrderEvent> = JsonDecoder::new();
488
489 while begin < max {
490 let end = rand::random_range(begin..=max);
491 let mut buf = BytesMut::from(&raw_input[begin..end]);
492 while !buf.is_empty() {
493 if let Some(event) = dec.decode(&mut buf).unwrap() {
494 unique_events.insert(event.item);
495 event_count += 1;
496 }
497 }
498 begin = end;
499 }
500
501 while let Some(event) = dec.decode_eof(&mut Default::default()).unwrap() {
502 unique_events.insert(event.item);
503 event_count += 1;
504 }
505
506 assert_eq!(28, event_count);
507 assert_eq!(22, unique_events.len());
508 }
509 }
510}