http_streams_core/
json_array_codec.rs1use crate::error::{StreamError, StreamErrorKind};
9use bytes::{Buf, BytesMut};
10use serde::Deserialize;
11use std::marker::PhantomData;
12
13#[derive(Clone, Debug)]
15pub struct JsonArrayCodec<T> {
16 max_length: usize,
17 json_cursor: JsonCursor,
18 _ph: PhantomData<fn() -> T>,
23}
24
25#[derive(Clone, Debug)]
26struct JsonCursor {
27 current_offset: usize,
28 array_is_opened: bool,
29 delimiter_expected: bool,
30 quote_opened: bool,
31 escaped: bool,
32 opened_brackets: usize,
33 current_obj_pos: usize,
34 current_primitive_start: Option<usize>,
37}
38
39impl<T> JsonArrayCodec<T> {
40 pub fn new_with_max_length(max_length: usize) -> Self {
42 let initial_cursor = JsonCursor {
43 current_offset: 0,
44 array_is_opened: false,
45 delimiter_expected: false,
46 quote_opened: false,
47 escaped: false,
48 opened_brackets: 0,
49 current_obj_pos: 0,
50 current_primitive_start: None,
51 };
52
53 JsonArrayCodec {
54 max_length,
55 json_cursor: initial_cursor,
56 _ph: PhantomData,
57 }
58 }
59}
60
61fn codec_error(err: serde_json::Error) -> StreamError {
62 StreamError::new(StreamErrorKind::CodecError, Some(Box::new(err)), None)
63}
64
65impl<T> tokio_util::codec::Decoder for JsonArrayCodec<T>
66where
67 T: for<'de> Deserialize<'de>,
68{
69 type Item = Result<T, StreamError>;
72 type Error = StreamError;
73
74 fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<Self::Item>, StreamError> {
75 if buf.is_empty() {
76 return Ok(None);
77 }
78
79 for (position, current_ch) in buf[self.json_cursor.current_offset..buf.len()]
80 .iter()
81 .enumerate()
82 {
83 let abs_pos = self.json_cursor.current_offset + position;
84
85 if abs_pos >= self.max_length {
86 return Err(StreamError::new(
87 StreamErrorKind::MaxLenReachedError,
88 None,
89 Some("Max object length reached".into()),
90 ));
91 }
92
93 match *current_ch {
94 b'[' if !self.json_cursor.quote_opened && self.json_cursor.opened_brackets == 0 => {
95 if self.json_cursor.array_is_opened {
96 self.json_cursor.current_obj_pos = abs_pos;
98 self.json_cursor.opened_brackets += 1;
99 self.json_cursor.current_primitive_start = None;
100 } else {
101 self.json_cursor.array_is_opened = true;
102 }
103 }
104 b'[' if !self.json_cursor.quote_opened && self.json_cursor.opened_brackets > 0 => {
105 self.json_cursor.opened_brackets += 1;
106 self.json_cursor.escaped = false;
107 }
108 b']' if !self.json_cursor.quote_opened && self.json_cursor.opened_brackets == 0 => {
109 if let Some(prim_start) = self.json_cursor.current_primitive_start.take() {
111 let obj_slice = trim_ascii(&buf[prim_start..abs_pos]);
112 if !obj_slice.is_empty() {
113 let result = serde_json::from_slice(obj_slice).map_err(codec_error);
114 buf.advance(abs_pos + 1);
115 self.json_cursor.current_offset = 0;
116 self.json_cursor.delimiter_expected = false;
117 return result.map(|item| Some(Ok(item)));
118 }
119 }
120 }
121 b']' if !self.json_cursor.quote_opened && self.json_cursor.opened_brackets > 0 => {
122 self.json_cursor.opened_brackets -= 1;
123 self.json_cursor.escaped = false;
124 if self.json_cursor.opened_brackets == 0 {
125 self.json_cursor.delimiter_expected = true;
127 let obj_slice = &buf[self.json_cursor.current_obj_pos..abs_pos + 1];
128 let result = serde_json::from_slice(obj_slice).map_err(codec_error);
129 self.json_cursor.current_obj_pos = 0;
130 buf.advance(abs_pos + 1);
131 self.json_cursor.current_offset = 0;
132 return result.map(|item| Some(Ok(item)));
133 }
134 }
135 b'"' if !self.json_cursor.escaped && self.json_cursor.opened_brackets == 0 => {
136 if self.json_cursor.quote_opened {
137 self.json_cursor.quote_opened = false;
139 if let Some(prim_start) = self.json_cursor.current_primitive_start.take() {
140 self.json_cursor.delimiter_expected = true;
141 let obj_slice = &buf[prim_start..abs_pos + 1];
142 let result = serde_json::from_slice(obj_slice).map_err(codec_error);
143 buf.advance(abs_pos + 1);
144 self.json_cursor.current_offset = 0;
145 return result.map(|item| Some(Ok(item)));
146 }
147 } else {
148 self.json_cursor.quote_opened = true;
150 if self.json_cursor.current_primitive_start.is_none() {
151 self.json_cursor.current_primitive_start = Some(abs_pos);
152 }
153 }
154 }
155 b'"' if !self.json_cursor.escaped => {
156 self.json_cursor.quote_opened = !self.json_cursor.quote_opened;
158 }
159 b'\\' if self.json_cursor.quote_opened => {
160 self.json_cursor.escaped = !self.json_cursor.escaped;
161 }
162 b'{' if !self.json_cursor.quote_opened => {
163 if self.json_cursor.opened_brackets == 0 {
164 self.json_cursor.current_obj_pos = abs_pos;
165 self.json_cursor.current_primitive_start = None;
166 }
167 self.json_cursor.opened_brackets += 1;
168 self.json_cursor.escaped = false;
169 }
170 b'}' if !self.json_cursor.quote_opened && self.json_cursor.opened_brackets == 0 => {
174 return Err(StreamError::new(
175 StreamErrorKind::CodecError,
176 None,
177 Some("Unexpected `}` outside any object".into()),
178 ));
179 }
180 b'}' if !self.json_cursor.quote_opened => {
181 self.json_cursor.opened_brackets -= 1;
182 self.json_cursor.escaped = false;
183 if self.json_cursor.opened_brackets == 0 {
184 self.json_cursor.delimiter_expected = true;
185 let obj_slice = &buf[self.json_cursor.current_obj_pos..abs_pos + 1];
186 let result = serde_json::from_slice(obj_slice).map_err(codec_error);
187 self.json_cursor.current_obj_pos = 0;
188 buf.advance(abs_pos + 1);
189 self.json_cursor.current_offset = 0;
190 return result.map(|item| Some(Ok(item)));
191 }
192 }
193 b',' if !self.json_cursor.quote_opened && self.json_cursor.opened_brackets == 0 => {
194 if let Some(prim_start) = self.json_cursor.current_primitive_start.take() {
195 let obj_slice = trim_ascii(&buf[prim_start..abs_pos]);
196 if !obj_slice.is_empty() {
197 let result = serde_json::from_slice(obj_slice).map_err(codec_error);
198 buf.advance(abs_pos + 1);
199 self.json_cursor.current_offset = 0;
200 self.json_cursor.delimiter_expected = false;
201 return result.map(|item| Some(Ok(item)));
202 }
203 } else if !self.json_cursor.delimiter_expected {
204 return Err(StreamError::new(
205 StreamErrorKind::CodecError,
206 None,
207 Some("Unexpected delimiter found".into()),
208 ));
209 }
210 self.json_cursor.delimiter_expected = false;
211 }
212 _ if !self.json_cursor.quote_opened
213 && self.json_cursor.opened_brackets == 0
214 && self.json_cursor.array_is_opened
215 && !current_ch.is_ascii_whitespace() =>
216 {
217 if self.json_cursor.current_primitive_start.is_none() {
219 self.json_cursor.current_primitive_start = Some(abs_pos);
220 }
221 self.json_cursor.escaped = false;
222 }
223 _ => {
224 self.json_cursor.escaped = false;
225 }
226 }
227 }
228 self.json_cursor.current_offset = buf.len();
229
230 Ok(None)
231 }
232
233 fn decode_eof(&mut self, buf: &mut BytesMut) -> Result<Option<Self::Item>, StreamError> {
234 self.decode(buf)
235 }
236}
237
238fn trim_ascii(bytes: &[u8]) -> &[u8] {
239 let start = bytes
240 .iter()
241 .position(|b| !b.is_ascii_whitespace())
242 .unwrap_or(bytes.len());
243 let end = bytes
244 .iter()
245 .rposition(|b| !b.is_ascii_whitespace())
246 .map(|i| i + 1)
247 .unwrap_or(0);
248 if start >= end {
249 &[]
250 } else {
251 &bytes[start..end]
252 }
253}