Skip to main content

fixed_json/
serializer.rs

1use core::fmt::{self, Write};
2
3use crate::{Error, Result};
4
5macro_rules! integer_writer {
6    ($name:ident, $ty:ty) => {
7        pub fn $name(&mut self, value: $ty) -> Result<()> {
8            write_display(self, value)
9        }
10    };
11}
12
13#[derive(Clone, Copy, Eq, PartialEq)]
14enum FrameKind {
15    Object,
16    Array,
17}
18
19#[derive(Clone, Copy)]
20struct Frame {
21    kind: FrameKind,
22    first: bool,
23    expecting_value: bool,
24}
25
26impl Frame {
27    #[inline]
28    const fn new(kind: FrameKind) -> Self {
29        Self {
30            kind,
31            first: true,
32            expecting_value: false,
33        }
34    }
35}
36
37/// Streaming JSON serializer that writes into caller-owned fixed storage.
38///
39/// The serializer never allocates. `DEPTH` is the maximum number of open
40/// arrays/objects tracked by the internal stack.
41pub struct JsonSerializer<'a, const DEPTH: usize> {
42    out: &'a mut [u8],
43    len: usize,
44    stack: [Frame; DEPTH],
45    depth: usize,
46    root_written: bool,
47}
48
49impl<'a, const DEPTH: usize> JsonSerializer<'a, DEPTH> {
50    #[inline]
51    pub fn new(out: &'a mut [u8]) -> Self {
52        Self {
53            out,
54            len: 0,
55            stack: [Frame::new(FrameKind::Array); DEPTH],
56            depth: 0,
57            root_written: false,
58        }
59    }
60
61    #[inline]
62    pub fn len(&self) -> usize {
63        self.len
64    }
65
66    #[inline]
67    pub fn is_empty(&self) -> bool {
68        self.len == 0
69    }
70
71    #[inline]
72    pub fn capacity(&self) -> usize {
73        self.out.len()
74    }
75
76    #[inline]
77    pub fn as_str(&self) -> &str {
78        // SAFETY: all bytes are written from UTF-8 string literals, input `str`
79        // slices, or ASCII escape sequences.
80        unsafe { core::str::from_utf8_unchecked(&self.out[..self.len]) }
81    }
82
83    #[inline]
84    pub fn finish(&self) -> Result<&str> {
85        if self.depth == 0 && self.root_written {
86            Ok(self.as_str())
87        } else if self.depth == 0 {
88            Err(Error::BadSerialize)
89        } else {
90            Err(Error::NestMismatch)
91        }
92    }
93
94    #[inline]
95    pub fn reset(&mut self) {
96        self.len = 0;
97        self.depth = 0;
98        self.root_written = false;
99    }
100
101    pub fn begin_object(&mut self) -> Result<()> {
102        begin_container(self, FrameKind::Object, b'{')
103    }
104
105    pub fn end_object(&mut self) -> Result<()> {
106        end_container(self, FrameKind::Object, b'}')
107    }
108
109    pub fn begin_array(&mut self) -> Result<()> {
110        begin_container(self, FrameKind::Array, b'[')
111    }
112
113    pub fn end_array(&mut self) -> Result<()> {
114        end_container(self, FrameKind::Array, b']')
115    }
116
117    pub fn key(&mut self, key: &str) -> Result<()> {
118        let frame = current_frame_mut(self)?;
119        if frame.kind != FrameKind::Object || frame.expecting_value {
120            return Err(Error::BadSerialize);
121        }
122        if !frame.first {
123            write_byte(self, b',')?;
124        }
125        current_frame_mut(self)?.first = false;
126        write_quoted(self, key)?;
127        write_byte(self, b':')?;
128        current_frame_mut(self)?.expecting_value = true;
129        Ok(())
130    }
131
132    pub fn null(&mut self) -> Result<()> {
133        write_value_str(self, "null")
134    }
135
136    pub fn bool(&mut self, value: bool) -> Result<()> {
137        write_value_str(self, if value { "true" } else { "false" })
138    }
139
140    pub fn string(&mut self, value: &str) -> Result<()> {
141        before_value(self)?;
142        write_quoted(self, value)
143    }
144
145    integer_writer!(i16, i16);
146    integer_writer!(u16, u16);
147    integer_writer!(i32, i32);
148    integer_writer!(u32, u32);
149    integer_writer!(i64, i64);
150    integer_writer!(u64, u64);
151
152    pub fn f64(&mut self, value: f64) -> Result<()> {
153        if !value.is_finite() {
154            return Err(Error::BadNum);
155        }
156        write_display(self, value)
157    }
158
159    pub fn raw_number(&mut self, number: &str) -> Result<()> {
160        if !json_number(number.as_bytes()) {
161            return Err(Error::BadNum);
162        }
163        write_value_str(self, number)
164    }
165}
166
167fn begin_container<const DEPTH: usize>(
168    serializer: &mut JsonSerializer<'_, DEPTH>,
169    kind: FrameKind,
170    open: u8,
171) -> Result<()> {
172    if serializer.depth == DEPTH {
173        return Err(Error::NestTooDeep);
174    }
175    before_value(serializer)?;
176    write_byte(serializer, open)?;
177    serializer.stack[serializer.depth] = Frame::new(kind);
178    serializer.depth += 1;
179    Ok(())
180}
181
182fn end_container<const DEPTH: usize>(
183    serializer: &mut JsonSerializer<'_, DEPTH>,
184    kind: FrameKind,
185    close: u8,
186) -> Result<()> {
187    if serializer.depth == 0 {
188        return Err(Error::NestMismatch);
189    }
190    let frame = serializer.stack[serializer.depth - 1];
191    if frame.kind != kind || frame.expecting_value {
192        return Err(Error::NestMismatch);
193    }
194    serializer.depth -= 1;
195    write_byte(serializer, close)
196}
197
198fn before_value<const DEPTH: usize>(serializer: &mut JsonSerializer<'_, DEPTH>) -> Result<()> {
199    if serializer.depth == 0 {
200        if serializer.root_written {
201            return Err(Error::BadSerialize);
202        }
203        serializer.root_written = true;
204        return Ok(());
205    }
206
207    let frame = &mut serializer.stack[serializer.depth - 1];
208    match frame.kind {
209        FrameKind::Array => {
210            if !frame.first {
211                write_byte(serializer, b',')?;
212            }
213            serializer.stack[serializer.depth - 1].first = false;
214            Ok(())
215        }
216        FrameKind::Object if frame.expecting_value => {
217            serializer.stack[serializer.depth - 1].expecting_value = false;
218            Ok(())
219        }
220        FrameKind::Object => Err(Error::BadSerialize),
221    }
222}
223
224#[inline]
225fn current_frame_mut<'s, 'out, const DEPTH: usize>(
226    serializer: &'s mut JsonSerializer<'out, DEPTH>,
227) -> Result<&'s mut Frame> {
228    if serializer.depth == 0 {
229        Err(Error::BadSerialize)
230    } else {
231        Ok(&mut serializer.stack[serializer.depth - 1])
232    }
233}
234
235fn write_value_str<const DEPTH: usize>(
236    serializer: &mut JsonSerializer<'_, DEPTH>,
237    value: &str,
238) -> Result<()> {
239    before_value(serializer)?;
240    write_raw_str(serializer, value)
241}
242
243fn write_display<const DEPTH: usize>(
244    serializer: &mut JsonSerializer<'_, DEPTH>,
245    value: impl fmt::Display,
246) -> Result<()> {
247    before_value(serializer)?;
248    write!(serializer, "{value}").map_err(|_| Error::WriteLong)
249}
250
251fn write_quoted<const DEPTH: usize>(
252    serializer: &mut JsonSerializer<'_, DEPTH>,
253    value: &str,
254) -> Result<()> {
255    write_byte(serializer, b'"')?;
256    for ch in value.chars() {
257        match ch {
258            '"' => write_raw_str(serializer, "\\\"")?,
259            '\\' => write_raw_str(serializer, "\\\\")?,
260            '\u{08}' => write_raw_str(serializer, "\\b")?,
261            '\u{0c}' => write_raw_str(serializer, "\\f")?,
262            '\n' => write_raw_str(serializer, "\\n")?,
263            '\r' => write_raw_str(serializer, "\\r")?,
264            '\t' => write_raw_str(serializer, "\\t")?,
265            '\u{00}'..='\u{1f}' => {
266                write_raw_str(serializer, "\\u00")?;
267                write_hex_digit(serializer, (ch as u8) >> 4)?;
268                write_hex_digit(serializer, ch as u8)?;
269            }
270            _ => write_raw_str(serializer, ch.encode_utf8(&mut [0; 4]))?,
271        }
272    }
273    write_byte(serializer, b'"')
274}
275
276#[inline]
277fn write_hex_digit<const DEPTH: usize>(
278    serializer: &mut JsonSerializer<'_, DEPTH>,
279    value: u8,
280) -> Result<()> {
281    const HEX: &[u8; 16] = b"0123456789abcdef";
282    write_byte(serializer, HEX[(value & 0x0f) as usize])
283}
284
285#[inline]
286fn write_byte<const DEPTH: usize>(
287    serializer: &mut JsonSerializer<'_, DEPTH>,
288    byte: u8,
289) -> Result<()> {
290    if serializer.len == serializer.out.len() {
291        return Err(Error::WriteLong);
292    }
293    serializer.out[serializer.len] = byte;
294    serializer.len += 1;
295    Ok(())
296}
297
298#[inline]
299fn write_raw_str<const DEPTH: usize>(
300    serializer: &mut JsonSerializer<'_, DEPTH>,
301    value: &str,
302) -> Result<()> {
303    if serializer.out.len() - serializer.len < value.len() {
304        return Err(Error::WriteLong);
305    }
306    serializer.out[serializer.len..serializer.len + value.len()].copy_from_slice(value.as_bytes());
307    serializer.len += value.len();
308    Ok(())
309}
310
311impl<const DEPTH: usize> fmt::Write for JsonSerializer<'_, DEPTH> {
312    #[inline]
313    fn write_str(&mut self, s: &str) -> fmt::Result {
314        write_raw_str(self, s).map_err(|_| fmt::Error)
315    }
316}
317
318fn json_number(bytes: &[u8]) -> bool {
319    if bytes.is_empty() {
320        return false;
321    }
322    let mut i = 0usize;
323    if bytes[i] == b'-' {
324        i += 1;
325    }
326    if i >= bytes.len() || !bytes[i].is_ascii_digit() {
327        return false;
328    }
329    if bytes[i] == b'0' {
330        i += 1;
331        if i < bytes.len() && bytes[i].is_ascii_digit() {
332            return false;
333        }
334    } else {
335        while i < bytes.len() && bytes[i].is_ascii_digit() {
336            i += 1;
337        }
338    }
339    if i < bytes.len() && bytes[i] == b'.' {
340        i += 1;
341        if i >= bytes.len() || !bytes[i].is_ascii_digit() {
342            return false;
343        }
344        while i < bytes.len() && bytes[i].is_ascii_digit() {
345            i += 1;
346        }
347    }
348    if i < bytes.len() && matches!(bytes[i], b'e' | b'E') {
349        i += 1;
350        if i < bytes.len() && matches!(bytes[i], b'+' | b'-') {
351            i += 1;
352        }
353        if i >= bytes.len() || !bytes[i].is_ascii_digit() {
354            return false;
355        }
356        while i < bytes.len() && bytes[i].is_ascii_digit() {
357            i += 1;
358        }
359    }
360    i == bytes.len()
361}