json_codec_wasm/
encoder.rs

1//! JSON ([RFC 7159](http://tools.ietf.org/html/rfc7159)) encoder.
2//!
3//! # Usage example
4//!
5//! ```
6//! use json_codec_wasm::Encoder;
7//! use std::io::Cursor;
8//!
9//! let mut e = Encoder::new(Cursor::new(Vec::new()));
10//! let r = e.object().and_then(|()| {
11//!     e.key("key1")?; e.array()?;
12//!         for i in 0 .. 10 {
13//!             e.bool(i % 2 == 0)?
14//!         }
15//!     e.end()?;
16//!     e.key("key2")?; e.string("\"hello world\"")?;
17//!     e.key("key3")?; e.object()?;
18//!         e.key("inner1")?; e.bool(true)?;
19//!         e.key("inner2")?; e.array()?;
20//!             e.string("\u{2764}\u{fe0f}")?;
21//!             e.string("again")?;
22//!             e.bool(false)?;
23//!             e.usize(1024)?;
24//!             e.u8(90)?;
25//!             e.i128(-100)?;
26//!             e.null()?;
27//!         e.end()?;
28//!     e.end()?;
29//! e.end()});
30//! assert!(r.is_ok())
31
32use std::borrow::{Borrow, Cow};
33use std::error::Error;
34use std::fmt;
35use std::io::{self, Write};
36use std::str::Chars;
37
38use ast::Json;
39use stack::{Scope, Stack};
40
41// ToJson trait /////////////////////////////////////////////////////////////
42
43pub trait ToJson {
44    fn encode<W: Write>(&self, e: &mut Encoder<W>) -> EncodeResult<()>;
45}
46
47macro_rules! instance {
48    ($name: ident) => {
49        impl ToJson for $name {
50            fn encode<W: Write>(&self, e: &mut Encoder<W>) -> EncodeResult<()> {
51                e.$name(*self)
52            }
53        }
54    };
55}
56
57instance!(bool);
58instance!(u8);
59instance!(u16);
60instance!(u32);
61instance!(u64);
62instance!(usize);
63instance!(i8);
64instance!(i16);
65instance!(i32);
66instance!(i64);
67instance!(isize);
68instance!(i128);
69instance!(u128);
70
71impl ToJson for str {
72    fn encode<W: Write>(&self, e: &mut Encoder<W>) -> EncodeResult<()> {
73        e.string(self)
74    }
75}
76
77impl ToJson for String {
78    fn encode<W: Write>(&self, e: &mut Encoder<W>) -> EncodeResult<()> {
79        e.string(self.as_str())
80    }
81}
82
83impl ToJson for Json {
84    fn encode<W: Write>(&self, e: &mut Encoder<W>) -> EncodeResult<()> {
85        e.encode(self)
86    }
87}
88
89impl<'a, T: ToJson> ToJson for &'a T {
90    fn encode<W: Write>(&self, e: &mut Encoder<W>) -> EncodeResult<()> {
91        (*self).encode(e)
92    }
93}
94
95impl<'a, T: ToJson + Clone> ToJson for Cow<'a, T> {
96    fn encode<W: Write>(&self, e: &mut Encoder<W>) -> EncodeResult<()> {
97        (**self).encode(e)
98    }
99}
100
101impl<T: ToJson> ToJson for Option<T> {
102    fn encode<W: Write>(&self, e: &mut Encoder<W>) -> EncodeResult<()> {
103        e.optional(self.as_ref())
104    }
105}
106
107impl<'a, T: ToJson> ToJson for &'a [T] {
108    fn encode<W: Write>(&self, e: &mut Encoder<W>) -> EncodeResult<()> {
109        e.array()?;
110        for x in *self {
111            x.encode(e)?
112        }
113        e.end()
114    }
115}
116
117// Encoder //////////////////////////////////////////////////////////////////
118
119/// JSON encoder over any `Write`-type.
120pub struct Encoder<W> {
121    writer: W,
122    stack: Stack,
123}
124
125// Macros ///////////////////////////////////////////////////////////////////
126
127macro_rules! number {
128    ($name: ident, i128) => {
129        pub fn $name(&mut self, x: i128) -> EncodeResult<()> {
130            // if x.is_nan() || x.is_infinite() {
131            //     return Err(EncodeError::InvalidFloat)
132            // }
133            self.comma_array()?;
134            self.writer.write_all(x.to_string().as_bytes())?;
135            Ok(())
136        }
137    };
138    ($name: ident, $ty: ty) => {
139        pub fn $name(&mut self, x: $ty) -> EncodeResult<()> {
140            self.comma_array()?;
141            self.writer.write_all(x.to_string().as_bytes())?;
142            Ok(())
143        }
144    };
145}
146
147impl<W: Write> Encoder<W> {
148    pub fn new(w: W) -> Encoder<W> {
149        Encoder {
150            writer: w,
151            stack: Stack::new(),
152        }
153    }
154
155    pub fn into_writer(self) -> W {
156        self.writer
157    }
158
159    pub fn writer_mut(&mut self) -> &mut W {
160        &mut self.writer
161    }
162
163    pub fn to_json<T: ToJson>(&mut self, t: T) -> EncodeResult<()> {
164        t.encode(self)
165    }
166
167    pub fn encode(&mut self, j: &Json) -> EncodeResult<()> {
168        match *j {
169            Json::Null => self.null()?,
170            Json::Bool(x) => self.bool(x)?,
171            Json::I128(x) => self.i128(x)?,
172            Json::U128(x) => self.u128(x)?,
173            Json::String(ref x) => self.string(x.as_ref())?,
174            Json::Array(ref xs) => {
175                self.array()?;
176                for x in xs {
177                    self.encode(x)?
178                }
179                self.end()?
180            }
181            Json::Object(ref xs) => {
182                self.object()?;
183                for (k, v) in xs {
184                    self.key(k.as_ref())?;
185                    self.encode(v)?
186                }
187                self.end()?
188            }
189        }
190        Ok(())
191    }
192
193    number!(u8, u8);
194    number!(u16, u16);
195    number!(u32, u32);
196    number!(u64, u64);
197    number!(usize, usize);
198
199    number!(i8, i8);
200    number!(i16, i16);
201    number!(i32, i32);
202    number!(i64, i64);
203    number!(isize, isize);
204
205    number!(i128, i128);
206    number!(u128, u128);
207
208    pub fn bool(&mut self, x: bool) -> EncodeResult<()> {
209        self.comma_array()?;
210        self.writer.write_all(if x { b"true" } else { b"false" })?;
211        Ok(())
212    }
213
214    pub fn null(&mut self) -> EncodeResult<()> {
215        self.comma_array()?;
216        self.writer.write_all(b"null")?;
217        Ok(())
218    }
219
220    pub fn optional<T: ToJson>(&mut self, val: Option<T>) -> EncodeResult<()> {
221        match val {
222            None => self.null(),
223            Some(ref v) => self.to_json(v),
224        }
225    }
226
227    pub fn string<S: Borrow<str>>(&mut self, s: S) -> EncodeResult<()> {
228        self.comma_array()?;
229        self.writer.write_all(b"\"")?;
230        for x in Bytes::new(EscapedChars::new(s.borrow())) {
231            self.writer.write_all(&[x])?;
232        }
233        self.writer.write_all(b"\"")?;
234        Ok(())
235    }
236
237    pub fn key<S: Borrow<str>>(&mut self, key: S) -> EncodeResult<()> {
238        self.comma_object()?;
239        self.string(key.borrow())?;
240        self.writer.write_all(b":")?;
241        Ok(())
242    }
243
244    /// Begin encoding a new JSON array.
245    ///
246    /// Must be paired with a call to `Encoder::end()`.
247    pub fn array(&mut self) -> EncodeResult<()> {
248        self.comma_array()?;
249        self.writer.write_all(b"[")?;
250        self.stack.push(Scope::A(false));
251        Ok(())
252    }
253
254    /// Begin encoding a new JSON object.
255    ///
256    /// Must be paired with a call to `Encoder::end()`.
257    pub fn object(&mut self) -> EncodeResult<()> {
258        self.comma_array()?;
259        self.writer.write_all(b"{")?;
260        self.stack.push(Scope::O(false));
261        Ok(())
262    }
263
264    /// End a JSON array or object.
265    pub fn end(&mut self) -> EncodeResult<()> {
266        match self.stack.pop() {
267            Some(Scope::A(_)) => self.writer.write_all(b"]").map_err(From::from),
268            Some(Scope::O(_)) => self.writer.write_all(b"}").map_err(From::from),
269            None => Ok(()),
270        }
271    }
272
273    fn comma_array(&mut self) -> EncodeResult<()> {
274        match self.stack.top() {
275            Some(Scope::A(true)) => self.writer.write_all(b",").map_err(From::from),
276            Some(Scope::A(false)) => {
277                self.stack.set();
278                Ok(())
279            }
280            _ => Ok(()),
281        }
282    }
283
284    fn comma_object(&mut self) -> EncodeResult<()> {
285        match self.stack.top() {
286            Some(Scope::O(true)) => self.writer.write_all(b",").map_err(From::from),
287            Some(Scope::O(false)) => {
288                self.stack.set();
289                Ok(())
290            }
291            _ => Ok(()),
292        }
293    }
294}
295
296// Encoder Error Type ///////////////////////////////////////////////////////
297
298pub type EncodeResult<A> = Result<A, EncodeError>;
299
300#[derive(Debug)]
301pub enum EncodeError {
302    Io(io::Error),
303    /// A float value such as `NAN` or `INFINITY` was used.
304    InvalidFloat,
305    /// Generic error message.
306    Message(&'static str),
307    /// Some other error trait impl.
308    Other(Box<dyn Error + Send + Sync>),
309}
310
311impl fmt::Display for EncodeError {
312    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
313        match *self {
314            EncodeError::Io(ref e) => write!(f, "i/o: {:?}", e),
315            EncodeError::InvalidFloat => write!(f, "invalid f64 (NaN | Infinity)"),
316            EncodeError::Message(m) => write!(f, "error: {}", m),
317            EncodeError::Other(ref e) => write!(f, "other: {}", e),
318        }
319    }
320}
321
322impl Error for EncodeError {
323    fn description(&self) -> &str {
324        match *self {
325            EncodeError::Io(_) => "i/o error",
326            EncodeError::InvalidFloat => "invalid float value (e.g. NAN or INFINITY)",
327            EncodeError::Message(_) => "generic error message",
328            EncodeError::Other(_) => "other error",
329        }
330    }
331
332    fn cause(&self) -> Option<&dyn Error> {
333        match *self {
334            EncodeError::Io(ref e) => Some(e),
335            EncodeError::Other(ref e) => Some(&**e),
336            _ => None,
337        }
338    }
339}
340
341impl From<io::Error> for EncodeError {
342    fn from(e: io::Error) -> EncodeError {
343        EncodeError::Io(e)
344    }
345}
346
347// Character conversion support /////////////////////////////////////////////
348
349struct EscapedChars<'r> {
350    source: Chars<'r>,
351    buffer: [u8; 5],
352    index: Option<(usize, usize)>,
353}
354
355impl<'r> EscapedChars<'r> {
356    fn new(s: &'r str) -> EscapedChars<'r> {
357        EscapedChars {
358            source: s.chars(),
359            buffer: [0; 5],
360            index: None,
361        }
362    }
363
364    fn chr(x: u8) -> u8 {
365        match x {
366            0x0..=0x9 => b'0' + x,
367            0xA..=0xF => b'A' + x - 0xA,
368            _ => panic!("{} > 0xF", x),
369        }
370    }
371}
372
373impl<'r> Iterator for EscapedChars<'r> {
374    type Item = char;
375
376    fn next(&mut self) -> Option<char> {
377        match self.index {
378            None => (),
379            Some((i, e)) => {
380                if i < e {
381                    self.index = Some((i + 1, e));
382                    return Some(self.buffer[i] as char);
383                } else {
384                    self.index = None
385                }
386            }
387        }
388        match self.source.next() {
389            Some(x @ '\\') | Some(x @ '"') => {
390                self.buffer[0] = x as u8;
391                self.index = Some((0, 1));
392                Some('\\')
393            }
394            Some('\n') => {
395                self.buffer[0] = b'n';
396                self.index = Some((0, 1));
397                Some('\\')
398            }
399            Some('\t') => {
400                self.buffer[0] = b't';
401                self.index = Some((0, 1));
402                Some('\\')
403            }
404            Some('\r') => {
405                self.buffer[0] = b'r';
406                self.index = Some((0, 1));
407                Some('\\')
408            }
409            Some(x @ '\x00'..='\x1F') | Some(x @ '\x7F') => {
410                self.buffer[0] = b'u';
411                self.buffer[1] = b'0';
412                self.buffer[2] = b'0';
413                self.buffer[3] = Self::chr(x as u8 >> 4);
414                self.buffer[4] = Self::chr(x as u8 & 0x0F);
415                self.index = Some((0, 5));
416                Some('\\')
417            }
418            x => x,
419        }
420    }
421}
422
423struct Bytes<I> {
424    src: I,
425    buf: [u8; 4],
426    pos: usize,
427    end: usize,
428}
429
430impl<I> Bytes<I> {
431    pub fn new(i: I) -> Bytes<I> {
432        Bytes {
433            src: i,
434            buf: [0; 4],
435            pos: 0,
436            end: 0,
437        }
438    }
439}
440
441impl<I: Iterator<Item = char>> Iterator for Bytes<I> {
442    type Item = u8;
443
444    fn next(&mut self) -> Option<u8> {
445        if self.pos == self.end {
446            match self.src.next() {
447                Some(c) => {
448                    self.end = c.encode_utf8(&mut self.buf).len();
449                    debug_assert!(self.end > 0);
450                    self.pos = 0
451                }
452                None => return None,
453            }
454        }
455        let x = self.buf[self.pos];
456        self.pos += 1;
457        Some(x)
458    }
459}