deser_json/
ser.rs

1use deser::ser::SerializeDriver;
2use deser::{Atom, Error, ErrorKind, Event, Serialize};
3
4/// Serializes a serializable to JSON.
5pub struct Serializer {
6    out: String,
7}
8
9enum ContainerState {
10    Map { first: bool, key_pos: bool },
11    Seq { first: bool },
12}
13
14impl Default for Serializer {
15    fn default() -> Serializer {
16        Serializer::new()
17    }
18}
19
20impl Serializer {
21    /// Creates a new serializer that writes into the given writer.
22    pub fn new() -> Serializer {
23        Serializer { out: String::new() }
24    }
25
26    /// Serializes the given value.
27    pub fn serialize(mut self, value: &dyn Serialize) -> Result<String, Error> {
28        let mut driver = SerializeDriver::new(value);
29        let mut container_stack = Vec::new();
30
31        macro_rules! unsupported {
32            ($msg:expr) => {{
33                return Err(Error::new(ErrorKind::UnsupportedType, $msg));
34            }};
35        }
36
37        while let Some((event, _, _)) = driver.next()? {
38            // try to exit containers first
39            match event {
40                Event::MapEnd => {
41                    if !matches!(container_stack.pop(), Some(ContainerState::Map { .. })) {
42                        return Err(Error::new(ErrorKind::Unexpected, "unexpected map end"));
43                    }
44                    self.write_char('}');
45                    continue;
46                }
47                Event::SeqEnd => {
48                    if !matches!(container_stack.pop(), Some(ContainerState::Seq { .. })) {
49                        return Err(Error::new(ErrorKind::Unexpected, "unexpected array end"));
50                    }
51                    self.write_char(']');
52                    continue;
53                }
54                _ => {}
55            }
56
57            // do we need a comma?
58            if let Some(
59                ContainerState::Seq { first }
60                | ContainerState::Map {
61                    first,
62                    key_pos: true,
63                },
64            ) = container_stack.last_mut()
65            {
66                if !*first {
67                    self.write_char(',');
68                }
69                *first = false;
70            }
71
72            // keys need special handling
73            if let Some(ContainerState::Map { key_pos, .. }) = container_stack.last_mut() {
74                let is_key = *key_pos;
75                *key_pos = !*key_pos;
76                if is_key {
77                    match event {
78                        Event::Atom(Atom::Str(val)) => self.write_escaped_str(&val),
79                        Event::Atom(Atom::Char(c)) => {
80                            self.write_escaped_str(&(c as u32).to_string())
81                        }
82                        Event::Atom(Atom::U64(val)) => {
83                            self.write_char('"');
84                            self.write_str(&val.to_string());
85                            self.write_char('"');
86                        }
87                        Event::Atom(Atom::I64(val)) => {
88                            self.write_char('"');
89                            self.write_str(&val.to_string());
90                            self.write_char('"');
91                        }
92                        _ => unsupported!("JSON does not support this value for map keys"),
93                    }
94                    self.write_char(':');
95                    continue;
96                }
97            }
98
99            match event {
100                Event::Atom(atom) => match atom {
101                    Atom::Null => self.write_str("null"),
102                    Atom::Bool(true) => self.write_str("true"),
103                    Atom::Bool(false) => self.write_str("false"),
104                    Atom::Str(val) => self.write_escaped_str(&val),
105                    Atom::Bytes(_val) => unsupported!("JSON doesn't support bytes"),
106                    Atom::Char(c) => self.write_escaped_str(&(c as u32).to_string()),
107                    Atom::U64(val) => {
108                        #[cfg(feature = "speedups")]
109                        {
110                            self.write_str(itoa::Buffer::new().format(val))
111                        }
112                        #[cfg(not(feature = "speedups"))]
113                        {
114                            self.write_str(&val.to_string())
115                        }
116                    }
117                    Atom::I64(val) => {
118                        #[cfg(feature = "speedups")]
119                        {
120                            self.write_str(itoa::Buffer::new().format(val))
121                        }
122                        #[cfg(not(feature = "speedups"))]
123                        {
124                            self.write_str(&val.to_string())
125                        }
126                    }
127                    Atom::F64(val) => {
128                        if val.is_finite() {
129                            #[cfg(feature = "speedups")]
130                            {
131                                self.write_str(ryu::Buffer::new().format_finite(val))
132                            }
133                            #[cfg(not(feature = "speedups"))]
134                            {
135                                self.write_str(val.to_string().as_str())
136                            }
137                        } else {
138                            self.write_str("null")
139                        }
140                    }
141                    _ => unsupported!("unknown atom"),
142                },
143                Event::MapStart => {
144                    container_stack.push(ContainerState::Map {
145                        first: true,
146                        key_pos: true,
147                    });
148                    self.write_char('{')
149                }
150                Event::SeqStart => {
151                    container_stack.push(ContainerState::Seq { first: true });
152                    self.write_char('[')
153                }
154                Event::SeqEnd | Event::MapEnd => unreachable!(),
155            }
156        }
157
158        Ok(self.out)
159    }
160
161    fn write_str(&mut self, s: &str) {
162        self.out.push_str(s);
163    }
164
165    fn write_char(&mut self, c: char) {
166        self.out.push(c);
167    }
168
169    fn write_escaped_str(&mut self, value: &str) {
170        self.write_char('"');
171
172        let bytes = value.as_bytes();
173        let mut start = 0;
174
175        for (i, &byte) in bytes.iter().enumerate() {
176            let escape = ESCAPE[byte as usize];
177            if escape == 0 {
178                continue;
179            }
180
181            if start < i {
182                self.write_str(&value[start..i]);
183            }
184
185            match escape {
186                self::BB => self.write_str("\\b"),
187                self::TT => self.write_str("\\t"),
188                self::NN => self.write_str("\\n"),
189                self::FF => self.write_str("\\f"),
190                self::RR => self.write_str("\\r"),
191                self::QU => self.write_str("\\\""),
192                self::BS => self.write_str("\\\\"),
193                self::U => {
194                    static HEX_DIGITS: [u8; 16] = *b"0123456789abcdef";
195                    self.write_str("\\u00");
196                    self.write_char(HEX_DIGITS[(byte >> 4) as usize] as char);
197                    self.write_char(HEX_DIGITS[(byte & 0xF) as usize] as char);
198                }
199                _ => unreachable!(),
200            }
201
202            start = i + 1;
203        }
204
205        if start != bytes.len() {
206            self.write_str(&value[start..]);
207        }
208
209        self.write_char('"');
210    }
211}
212
213const BB: u8 = b'b'; // \x08
214const TT: u8 = b't'; // \x09
215const NN: u8 = b'n'; // \x0A
216const FF: u8 = b'f'; // \x0C
217const RR: u8 = b'r'; // \x0D
218const QU: u8 = b'"'; // \x22
219const BS: u8 = b'\\'; // \x5C
220const U: u8 = b'u'; // \x00...\x1F except the ones above
221
222// Lookup table of escape sequences. A value of b'x' at index i means that byte
223// i is escaped as "\x" in JSON. A value of 0 means that byte i is not escaped.
224#[rustfmt::skip]
225static ESCAPE: [u8; 256] = [
226    //  1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
227    U,  U,  U,  U,  U,  U,  U,  U, BB, TT, NN,  U, FF, RR,  U,  U, // 0
228    U,  U,  U,  U,  U,  U,  U,  U,  U,  U,  U,  U,  U,  U,  U,  U, // 1
229    0,  0, QU,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, // 2
230    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, // 3
231    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, // 4
232    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, BS,  0,  0,  0, // 5
233    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, // 6
234    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, // 7
235    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, // 8
236    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, // 9
237    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, // A
238    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, // B
239    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, // C
240    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, // D
241    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, // E
242    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, // F
243];
244
245/// Serializes a value to JSON.
246pub fn to_string(value: &dyn Serialize) -> Result<String, Error> {
247    Serializer::new().serialize(value)
248}