json_event_parser/
write.rs

1use crate::JsonEvent;
2use std::io::{Error, ErrorKind, Result, Write};
3#[cfg(feature = "async-tokio")]
4use tokio::io::{AsyncWrite, AsyncWriteExt};
5
6/// A JSON streaming writer writing to a [`Write`] implementation.
7///
8/// ```
9/// use json_event_parser::{JsonEvent, WriterJsonSerializer};
10///
11/// let mut writer = WriterJsonSerializer::new(Vec::new());
12/// writer.serialize_event(JsonEvent::StartObject)?;
13/// writer.serialize_event(JsonEvent::ObjectKey("foo".into()))?;
14/// writer.serialize_event(JsonEvent::Number("1".into()))?;
15/// writer.serialize_event(JsonEvent::EndObject)?;
16///
17/// assert_eq!(writer.finish()?.as_slice(), b"{\"foo\":1}");
18/// # std::io::Result::Ok(())
19/// ```
20pub struct WriterJsonSerializer<W: Write> {
21    write: W,
22    writer: LowLevelJsonSerializer,
23}
24
25impl<W: Write> WriterJsonSerializer<W> {
26    pub const fn new(write: W) -> Self {
27        Self {
28            write,
29            writer: LowLevelJsonSerializer::new(),
30        }
31    }
32
33    pub fn serialize_event(&mut self, event: JsonEvent<'_>) -> Result<()> {
34        self.writer.serialize_event(event, &mut self.write)
35    }
36
37    #[deprecated(note = "Use serialize_event() instead")]
38    pub fn write_event(&mut self, event: JsonEvent<'_>) -> Result<()> {
39        self.serialize_event(event)
40    }
41
42    pub fn finish(self) -> Result<W> {
43        self.writer.validate_eof()?;
44        Ok(self.write)
45    }
46}
47
48/// A JSON streaming writer writing to an [`AsyncWrite`] implementation.
49///
50/// ```
51/// use json_event_parser::{JsonEvent, TokioAsyncWriterJsonSerializer};
52///
53/// # #[tokio::main(flavor = "current_thread")]
54/// # async fn main() -> ::std::io::Result<()> {
55/// let mut writer = TokioAsyncWriterJsonSerializer::new(Vec::new());
56/// writer.serialize_event(JsonEvent::StartObject).await?;
57/// writer
58///     .serialize_event(JsonEvent::ObjectKey("foo".into()))
59///     .await?;
60/// writer
61///     .serialize_event(JsonEvent::Number("1".into()))
62///     .await?;
63/// writer.serialize_event(JsonEvent::EndObject).await?;
64/// assert_eq!(writer.finish()?.as_slice(), b"{\"foo\":1}");
65/// # Ok(())
66/// # }
67/// ```
68#[cfg(feature = "async-tokio")]
69pub struct TokioAsyncWriterJsonSerializer<W: AsyncWrite + Unpin> {
70    write: W,
71    writer: LowLevelJsonSerializer,
72    buffer: Vec<u8>,
73}
74
75#[cfg(feature = "async-tokio")]
76impl<W: AsyncWrite + Unpin> TokioAsyncWriterJsonSerializer<W> {
77    pub const fn new(write: W) -> Self {
78        Self {
79            write,
80            writer: LowLevelJsonSerializer::new(),
81            buffer: Vec::new(),
82        }
83    }
84
85    pub async fn serialize_event(&mut self, event: JsonEvent<'_>) -> Result<()> {
86        self.writer.serialize_event(event, &mut self.buffer)?;
87        self.write.write_all(&self.buffer).await?;
88        self.buffer.clear();
89        Ok(())
90    }
91
92    #[deprecated(note = "Use serialize_event() instead")]
93    pub async fn write_event(&mut self, event: JsonEvent<'_>) -> Result<()> {
94        self.serialize_event(event).await
95    }
96
97    pub fn finish(self) -> Result<W> {
98        self.writer.validate_eof()?;
99        Ok(self.write)
100    }
101}
102
103/// A low-level JSON streaming writer writing to a [`Write`] implementation.
104///
105/// YOu probably want to use [`WriterJsonSerializer`] instead.
106///
107/// ```
108/// use json_event_parser::{JsonEvent, LowLevelJsonSerializer};
109///
110/// let mut writer = LowLevelJsonSerializer::new();
111/// let mut output = Vec::new();
112/// writer.serialize_event(JsonEvent::StartObject, &mut output)?;
113/// writer.serialize_event(JsonEvent::ObjectKey("foo".into()), &mut output)?;
114/// writer.serialize_event(JsonEvent::Number("1".into()), &mut output)?;
115/// writer.serialize_event(JsonEvent::EndObject, &mut output)?;
116///
117/// assert_eq!(output.as_slice(), b"{\"foo\":1}");
118/// # std::io::Result::Ok(())
119/// ```
120
121#[derive(Default)]
122pub struct LowLevelJsonSerializer {
123    state_stack: Vec<JsonState>,
124    element_written: bool,
125}
126
127impl LowLevelJsonSerializer {
128    pub const fn new() -> Self {
129        Self {
130            state_stack: Vec::new(),
131            element_written: false,
132        }
133    }
134
135    pub fn serialize_event(&mut self, event: JsonEvent<'_>, mut write: impl Write) -> Result<()> {
136        match event {
137            JsonEvent::String(s) => {
138                self.before_value(&mut write)?;
139                write_escaped_json_string(&s, write)
140            }
141            JsonEvent::Number(number) => {
142                self.before_value(&mut write)?;
143                write.write_all(number.as_bytes())
144            }
145            JsonEvent::Boolean(b) => {
146                self.before_value(&mut write)?;
147                write.write_all(if b { b"true" } else { b"false" })
148            }
149            JsonEvent::Null => {
150                self.before_value(&mut write)?;
151                write.write_all(b"null")
152            }
153            JsonEvent::StartArray => {
154                self.before_value(&mut write)?;
155                self.state_stack.push(JsonState::OpenArray);
156                write.write_all(b"[")
157            }
158            JsonEvent::EndArray => match self.state_stack.pop() {
159                Some(JsonState::OpenArray) | Some(JsonState::ContinuationArray) => {
160                    write.write_all(b"]")
161                }
162                Some(s) => {
163                    self.state_stack.push(s);
164                    Err(Error::new(
165                        ErrorKind::InvalidInput,
166                        "Closing a not opened array",
167                    ))
168                }
169                None => Err(Error::new(
170                    ErrorKind::InvalidInput,
171                    "Closing a not opened array",
172                )),
173            },
174            JsonEvent::StartObject => {
175                self.before_value(&mut write)?;
176                self.state_stack.push(JsonState::OpenObject);
177                write.write_all(b"{")
178            }
179            JsonEvent::EndObject => match self.state_stack.pop() {
180                Some(JsonState::OpenObject) | Some(JsonState::ContinuationObject) => {
181                    write.write_all(b"}")
182                }
183                Some(s) => {
184                    self.state_stack.push(s);
185                    Err(Error::new(
186                        ErrorKind::InvalidInput,
187                        "Closing a not opened object",
188                    ))
189                }
190                None => Err(Error::new(
191                    ErrorKind::InvalidInput,
192                    "Closing a not opened object",
193                )),
194            },
195            JsonEvent::ObjectKey(key) => {
196                match self.state_stack.pop() {
197                    Some(JsonState::OpenObject) => (),
198                    Some(JsonState::ContinuationObject) => write.write_all(b",")?,
199                    _ => {
200                        return Err(Error::new(
201                            ErrorKind::InvalidInput,
202                            "Trying to write an object key in an not object",
203                        ))
204                    }
205                }
206                self.state_stack.push(JsonState::ContinuationObject);
207                self.state_stack.push(JsonState::ObjectValue);
208                write_escaped_json_string(&key, &mut write)?;
209                write.write_all(b":")
210            }
211            JsonEvent::Eof => Err(Error::new(
212                ErrorKind::InvalidInput,
213                "EOF is not allowed in JSON writer",
214            )),
215        }
216    }
217
218    #[deprecated(note = "Use serialize_event() instead")]
219    pub fn write_event(&mut self, event: JsonEvent<'_>, write: impl Write) -> Result<()> {
220        self.serialize_event(event, write)
221    }
222
223    fn before_value(&mut self, mut write: impl Write) -> Result<()> {
224        match self.state_stack.pop() {
225            Some(JsonState::OpenArray) => {
226                self.state_stack.push(JsonState::ContinuationArray);
227                Ok(())
228            }
229            Some(JsonState::ContinuationArray) => {
230                self.state_stack.push(JsonState::ContinuationArray);
231                write.write_all(b",")?;
232                Ok(())
233            }
234            Some(last_state @ JsonState::OpenObject)
235            | Some(last_state @ JsonState::ContinuationObject) => {
236                self.state_stack.push(last_state);
237                Err(Error::new(
238                    ErrorKind::InvalidInput,
239                    "Object key expected, string found",
240                ))
241            }
242            Some(JsonState::ObjectValue) => Ok(()),
243            None => {
244                if self.element_written {
245                    Err(Error::new(
246                        ErrorKind::InvalidInput,
247                        "A root JSON value has already been written",
248                    ))
249                } else {
250                    self.element_written = true;
251                    Ok(())
252                }
253            }
254        }
255    }
256
257    fn validate_eof(&self) -> Result<()> {
258        if !self.state_stack.is_empty() {
259            return Err(Error::new(
260                ErrorKind::InvalidInput,
261                "The written JSON is not balanced: an object or an array has not been closed",
262            ));
263        }
264        if !self.element_written {
265            return Err(Error::new(
266                ErrorKind::InvalidInput,
267                "A JSON file can't be empty",
268            ));
269        }
270        Ok(())
271    }
272}
273
274enum JsonState {
275    OpenArray,
276    ContinuationArray,
277    OpenObject,
278    ContinuationObject,
279    ObjectValue,
280}
281
282fn write_escaped_json_string(s: &str, mut write: impl Write) -> Result<()> {
283    write.write_all(b"\"")?;
284    let mut buffer = [b'\\', b'u', 0, 0, 0, 0];
285    for c in s.chars() {
286        match c {
287            '\\' => write.write_all(b"\\\\"),
288            '"' => write.write_all(b"\\\""),
289            c => {
290                if c < char::from(32) {
291                    match c {
292                        '\u{08}' => write.write_all(b"\\b"),
293                        '\u{0C}' => write.write_all(b"\\f"),
294                        '\n' => write.write_all(b"\\n"),
295                        '\r' => write.write_all(b"\\r"),
296                        '\t' => write.write_all(b"\\t"),
297                        c => {
298                            let mut c = c as u8;
299                            for i in (2..6).rev() {
300                                let ch = c % 16;
301                                buffer[i] = if ch < 10 { b'0' + ch } else { b'A' + ch - 10 };
302                                c /= 16;
303                            }
304                            write.write_all(&buffer)
305                        }
306                    }
307                } else {
308                    write.write_all(c.encode_utf8(&mut buffer[2..]).as_bytes())
309                }
310            }
311        }?;
312    }
313    write.write_all(b"\"")?;
314    Ok(())
315}