Skip to main content

dynamic/
json.rs

1use crate::assert_err;
2
3use super::Dynamic;
4use anyhow::{Result, anyhow};
5
6macro_rules! vec_to_json {
7    ($buf:expr, $vec:expr, $variant:ident) => {{
8        $buf.push('[');
9        let mut once = ZOnce::new("", ",");
10        for value in $vec.iter() {
11            $buf.push_str(once.take());
12            Dynamic::$variant(value.clone()).to_json($buf);
13        }
14        $buf.push(']');
15    }};
16}
17
18pub(crate) fn skip_white(buf: &[u8]) -> Result<usize> {
19    let mut pos = 0usize;
20    while pos < buf.len() && (buf[pos] == b' ' || buf[pos] == b'\r' || buf[pos] == b'\t' || buf[pos] == b'\n') {
21        pos += 1;
22    }
23    if pos < buf.len() { Ok(pos) } else { Err(anyhow!("no more data")) }
24}
25
26const TOKEN: &[u8] = b"01234567890.-+truefalsenull"; //合法的数字和其他 json token
27pub trait FromJson: Sized {
28    fn from_json(buf: &[u8]) -> Result<(Self, usize)>;
29    fn get_token(buf: &[u8]) -> Result<(&str, usize)> {
30        let mut pos = 0usize;
31        while pos < buf.len() && TOKEN.contains(&buf[pos]) {
32            pos += 1;
33        }
34        Ok((std::str::from_utf8(&buf[..pos])?, pos))
35    }
36
37    fn get_string(buf: &[u8]) -> Result<(String, usize)> {
38        let mut pos = 1usize;
39        let mut vec = Vec::new();
40        while pos < buf.len() && buf[pos] != b'"' {
41            if buf[pos] == b'\\' {
42                pos += 1;
43                if pos == buf.len() {
44                    return Err(anyhow!("uncomplete string"));
45                }
46                match buf[pos] {
47                    b'\\' => vec.push(b'\\'),
48                    b'"' => vec.push(b'\"'),
49                    b'r' => vec.push(b'\r'),
50                    b'n' => vec.push(b'\n'),
51                    b't' => vec.push(b'\t'),
52                    b'u' => {
53                        let unicode_str = unsafe { std::str::from_utf8_unchecked(&buf[(pos + 1)..(pos + 5)]) };
54                        if let Ok(unicode) = u32::from_str_radix(unicode_str, 16) {
55                            if unicode < 0x80 {
56                                vec.push(unicode as u8);
57                            } else {
58                                if let Some(unicode_char) = char::from_u32(unicode) {
59                                    unicode_char.encode_utf8(&mut vec);
60                                }
61                            }
62                        }
63                        pos += 4;
64                    }
65                    _ => {
66                        return Err(anyhow!("unknow escape {}", buf[pos]));
67                    }
68                }
69            } else {
70                vec.push(buf[pos]);
71            }
72            pos += 1;
73        }
74        if pos < buf.len() {
75            pos += 1;
76        }
77        Ok(String::from_utf8(vec).map(|s| (s, pos))?)
78    }
79}
80
81pub trait ToJson {
82    fn to_json(&self, buf: &mut String);
83}
84
85use indexmap::IndexMap;
86use parking_lot::RwLock;
87use smol_str::SmolStr;
88use std::sync::Arc;
89
90impl FromJson for Dynamic {
91    fn from_json(buf: &[u8]) -> Result<(Self, usize)> {
92        let mut pos = skip_white(buf)?;
93        if buf[pos] == b'[' {
94            pos += 1;
95            pos += skip_white(&buf[pos..])?;
96            let mut vec = Vec::<Self>::new();
97            while buf[pos] != b']' {
98                let (item, size) = Self::from_json(&buf[pos..])?;
99                vec.push(item);
100                pos += size;
101                pos += skip_white(&buf[pos..])?;
102                if buf[pos] == b',' {
103                    pos += 1;
104                    pos += skip_white(&buf[pos..])?;
105                }
106            }
107            Ok((Dynamic::List(Arc::new(RwLock::new(vec))), pos + 1))
108        } else if buf[pos] == b'{' {
109            pos += 1;
110            pos += skip_white(&buf[pos..])?;
111            let mut map = IndexMap::new();
112            while buf[pos] != b'}' {
113                assert_err!(buf[pos] != b'"', anyhow!("need a string key {:?}", String::from_utf8_lossy(&buf[pos..])));
114                let (key, size) = Self::get_string(&buf[pos..])?;
115                pos += size;
116                pos += skip_white(&buf[pos..])?;
117                assert_err!(buf[pos] != b':', anyhow!("need a :"));
118                pos += 1;
119                pos += skip_white(&buf[pos..])?;
120                let (item, size) = Self::from_json(&buf[pos..])?;
121                map.insert(SmolStr::from(key), item);
122                pos += size;
123                pos += skip_white(&buf[pos..])?;
124                if buf[pos] == b',' {
125                    pos += 1;
126                    pos += skip_white(&buf[pos..])?;
127                }
128            }
129            Ok((Dynamic::Map(Arc::new(RwLock::new(map))), pos + 1))
130        } else if buf[pos] == b'"' {
131            let (s, size) = Self::get_string(&buf[pos..])?;
132            Ok((SmolStr::from(s).into(), size))
133        } else {
134            let (token, size) = Self::get_token(&buf[pos..])?;
135            if token == "true" {
136                Ok((Dynamic::from(true), size))
137            } else if token == "false" {
138                Ok((Dynamic::from(false), size))
139            } else if token == "null" {
140                Ok((Dynamic::Null, size))
141            } else if token.contains('.') {
142                let v = token.parse::<f64>()?;
143                Ok((Dynamic::from(v), size))
144            } else {
145                let v = token.parse::<i64>()?;
146                Ok((Dynamic::from(v), size))
147            }
148        }
149    }
150}
151
152impl ToJson for &str {
153    fn to_json(&self, buf: &mut String) {
154        let mut formatted = self.as_bytes().iter().fold(vec![b'\"'], |mut vec, ch| match ch {
155            b'\"' => {
156                vec.extend_from_slice(&[0x5c, 0x22]);
157                vec
158            }
159            b'\\' => {
160                vec.extend_from_slice(&[0x5c, 0x5c]);
161                vec
162            }
163            b'\n' => {
164                vec.extend_from_slice(&[0x5c, 0x6e]);
165                vec
166            }
167            b'\r' => {
168                vec.extend_from_slice(&[0x5c, 0x72]);
169                vec
170            }
171            b'\t' => {
172                vec.extend_from_slice(&[0x5c, 0x74]);
173                vec
174            }
175            _ => {
176                vec.push(*ch);
177                vec
178            }
179        });
180        formatted.push(b'\"');
181        buf.push_str(unsafe { std::str::from_utf8_unchecked(&formatted) });
182    }
183}
184
185impl ToJson for i64 {
186    fn to_json(&self, buf: &mut String) {
187        buf.push_str(&self.to_string());
188    }
189}
190
191use super::ZOnce;
192
193impl ToJson for Dynamic {
194    fn to_json(&self, buf: &mut String) {
195        match self {
196            Self::Iter { idx: _, keys: _, value: _ } => {}
197            Self::Bool(b) => {
198                if *b {
199                    buf.push_str("true")
200                } else {
201                    buf.push_str("false")
202                }
203            }
204            Self::F16(bits) => buf.push_str(&super::f16_to_f64(*bits).to_string()),
205            Self::F32(f) => buf.push_str(&f.to_string()),
206            Self::F64(f) => buf.push_str(&f.to_string()),
207            Self::I8(i) => buf.push_str(&i.to_string()),
208            Self::I16(i) => buf.push_str(&i.to_string()),
209            Self::I32(i) => buf.push_str(&i.to_string()),
210            Self::I64(i) => buf.push_str(&i.to_string()),
211            Self::U8(i) => buf.push_str(&i.to_string()),
212            Self::U16(i) => buf.push_str(&i.to_string()),
213            Self::U32(i) => buf.push_str(&i.to_string()),
214            Self::U64(i) => buf.push_str(&i.to_string()),
215            Self::Null => buf.push_str("null"),
216            Self::String(s) => s.as_str().to_json(buf),
217            Self::StringBuf(s) => s.as_str().to_json(buf),
218            Self::Bytes(vec) => vec_to_json!(buf, vec, U8),
219            Self::VecI8(vec) => vec_to_json!(buf, vec, I8),
220            Self::VecU16(vec) => vec_to_json!(buf, vec, U16),
221            Self::VecI16(vec) => vec_to_json!(buf, vec, I16),
222            Self::VecU32(vec) => vec_to_json!(buf, vec, U32),
223            Self::VecI32(vec) => vec_to_json!(buf, vec, I32),
224            Self::VecF32(vec) => vec_to_json!(buf, vec, F32),
225            Self::VecU64(vec) => vec_to_json!(buf, vec, U64),
226            Self::VecI64(vec) => vec_to_json!(buf, vec, I64),
227            Self::VecF64(vec) => vec_to_json!(buf, vec, F64),
228            Self::List(a) => {
229                buf.push('[');
230                let mut once = ZOnce::new("", ",\n");
231                a.read().iter().for_each(|item| {
232                    buf.push_str(once.take());
233                    item.to_json(buf);
234                });
235                buf.push(']');
236            }
237            Self::Map(map) => {
238                buf.push('{');
239                let mut once = ZOnce::new("", ",\n");
240                map.read().iter().for_each(|(k, v)| {
241                    buf.push_str(once.take());
242                    k.as_str().to_json(buf);
243                    buf.push_str(": ");
244                    v.to_json(buf);
245                });
246                buf.push_str("}\n");
247            }
248            Self::Struct { .. } => {
249                buf.push('{');
250                let mut once = ZOnce::new("", ",\n");
251                self.keys().iter().for_each(|k| {
252                    buf.push_str(once.take());
253                    k.as_str().to_json(buf);
254                    buf.push_str(": ");
255                    self.get_dynamic(k).unwrap_or(Dynamic::Null).to_json(buf);
256                });
257                buf.push_str("}\n");
258            }
259            Self::Custom(value) => {
260                buf.push_str("{\"@custom\":");
261                value.custom_type_name().to_json(buf);
262                buf.push('}');
263            }
264        }
265    }
266}