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.-+eEtruefalsenull"; //合法的数字和其他 json token(含科学计数法 e/E)
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                        if pos + 5 > buf.len() {
54                            return Err(anyhow!("不完整的 unicode"));
55                        }
56                        let unicode_str = unsafe { std::str::from_utf8_unchecked(&buf[(pos + 1)..(pos + 5)]) };
57                        let Ok(unicode) = u32::from_str_radix(unicode_str, 16) else {
58                            return Err(anyhow!("非法 unicode 转义"));
59                        };
60                        pos += 4;
61                        // JSON 规范:高代理(0xD800..=0xDBFF)后必须跟 \uXXXX 低代理
62                        // (0xDC00..=0xDFFF),组合成完整 code point;孤立代理丢弃。
63                        let code = if (0xD800..=0xDBFF).contains(&unicode)
64                            && buf.get(pos + 1..pos + 3) == Some(b"\\u")
65                            && pos + 7 <= buf.len()
66                        {
67                            let low_str = unsafe { std::str::from_utf8_unchecked(&buf[(pos + 3)..(pos + 7)]) };
68                            if let Ok(low) = u32::from_str_radix(low_str, 16)
69                                && (0xDC00..=0xDFFF).contains(&low)
70                            {
71                                let combined = 0x10000 + ((unicode - 0xD800) << 10) + (low - 0xDC00);
72                                pos += 6;
73                                combined
74                            } else {
75                                unicode
76                            }
77                        } else {
78                            unicode
79                        };
80                        if code < 0x80 {
81                            vec.push(code as u8);
82                        } else if let Some(ch) = char::from_u32(code) {
83                            // encode_utf8 需要固定大小缓冲区,不能直接传 &mut Vec<u8>
84                            // (Vec 借用的是当前长度 0 的切片,会 panic)。
85                            let mut buf = [0u8; 4];
86                            let s = ch.encode_utf8(&mut buf);
87                            vec.extend_from_slice(s.as_bytes());
88                        }
89                    }
90                    _ => {
91                        return Err(anyhow!("unknow escape {}", buf[pos]));
92                    }
93                }
94            } else {
95                vec.push(buf[pos]);
96            }
97            pos += 1;
98        }
99        if pos < buf.len() {
100            pos += 1;
101        }
102        Ok(String::from_utf8(vec).map(|s| (s, pos))?)
103    }
104}
105
106pub trait ToJson {
107    fn to_json(&self, buf: &mut String);
108}
109
110use indexmap::IndexMap;
111use parking_lot::RwLock;
112use smol_str::SmolStr;
113use std::sync::Arc;
114
115impl FromJson for Dynamic {
116    fn from_json(buf: &[u8]) -> Result<(Self, usize)> {
117        let mut pos = skip_white(buf)?;
118        if buf[pos] == b'[' {
119            pos += 1;
120            pos += skip_white(&buf[pos..])?;
121            let mut vec = Vec::<Self>::new();
122            while buf[pos] != b']' {
123                let (item, size) = Self::from_json(&buf[pos..])?;
124                vec.push(item);
125                pos += size;
126                pos += skip_white(&buf[pos..])?;
127                if buf[pos] == b',' {
128                    pos += 1;
129                    pos += skip_white(&buf[pos..])?;
130                }
131            }
132            Ok((Dynamic::List(Arc::new(RwLock::new(vec))), pos + 1))
133        } else if buf[pos] == b'{' {
134            pos += 1;
135            pos += skip_white(&buf[pos..])?;
136            let mut map = IndexMap::new();
137            while buf[pos] != b'}' {
138                assert_err!(buf[pos] != b'"', anyhow!("need a string key {:?}", String::from_utf8_lossy(&buf[pos..])));
139                let (key, size) = Self::get_string(&buf[pos..])?;
140                pos += size;
141                pos += skip_white(&buf[pos..])?;
142                assert_err!(buf[pos] != b':', anyhow!("need a :"));
143                pos += 1;
144                pos += skip_white(&buf[pos..])?;
145                let (item, size) = Self::from_json(&buf[pos..])?;
146                map.insert(SmolStr::from(key), item);
147                pos += size;
148                pos += skip_white(&buf[pos..])?;
149                if buf[pos] == b',' {
150                    pos += 1;
151                    pos += skip_white(&buf[pos..])?;
152                }
153            }
154            Ok((Dynamic::Map(Arc::new(RwLock::new(map))), pos + 1))
155        } else if buf[pos] == b'"' {
156            let (s, size) = Self::get_string(&buf[pos..])?;
157            Ok((SmolStr::from(s).into(), size))
158        } else {
159            let (token, size) = Self::get_token(&buf[pos..])?;
160            if token == "true" {
161                Ok((Dynamic::from(true), size))
162            } else if token == "false" {
163                Ok((Dynamic::from(false), size))
164            } else if token == "null" {
165                Ok((Dynamic::Null, size))
166            } else if token.contains('.') || token.contains('e') || token.contains('E') {
167                let v = token.parse::<f64>()?;
168                Ok((Dynamic::from(v), size))
169            } else {
170                // 纯整数字面量;若失败(如溢出)退回 f64 而非直接报错。
171                match token.parse::<i64>() {
172                    Ok(v) => Ok((Dynamic::from(v), size)),
173                    Err(_) => {
174                        let v = token.parse::<f64>()?;
175                        Ok((Dynamic::from(v), size))
176                    }
177                }
178            }
179        }
180    }
181}
182
183impl ToJson for &str {
184    fn to_json(&self, buf: &mut String) {
185        let mut formatted = self.as_bytes().iter().fold(vec![b'\"'], |mut vec, ch| match ch {
186            b'\"' => {
187                vec.extend_from_slice(&[0x5c, 0x22]);
188                vec
189            }
190            b'\\' => {
191                vec.extend_from_slice(&[0x5c, 0x5c]);
192                vec
193            }
194            b'\n' => {
195                vec.extend_from_slice(&[0x5c, 0x6e]);
196                vec
197            }
198            b'\r' => {
199                vec.extend_from_slice(&[0x5c, 0x72]);
200                vec
201            }
202            b'\t' => {
203                vec.extend_from_slice(&[0x5c, 0x74]);
204                vec
205            }
206            0x08 => {
207                vec.extend_from_slice(&[0x5c, 0x62]); // \b
208                vec
209            }
210            0x0c => {
211                vec.extend_from_slice(&[0x5c, 0x66]); // \f
212                vec
213            }
214            c if *c < 0x20 => {
215                // 其它控制字符必须用 \uXXXX 转义(RFC 8259 §7),否则产生非法 JSON。
216                vec.extend_from_slice(format!("\\u{:04x}", c).as_bytes());
217                vec
218            }
219            _ => {
220                vec.push(*ch);
221                vec
222            }
223        });
224        formatted.push(b'\"');
225        buf.push_str(unsafe { std::str::from_utf8_unchecked(&formatted) });
226    }
227}
228
229impl ToJson for i64 {
230    fn to_json(&self, buf: &mut String) {
231        buf.push_str(&self.to_string());
232    }
233}
234
235use super::ZOnce;
236
237impl ToJson for Dynamic {
238    fn to_json(&self, buf: &mut String) {
239        match self {
240            Self::Iter { idx: _, keys: _, value: _ } => {}
241            Self::Bool(b) => {
242                if *b {
243                    buf.push_str("true")
244                } else {
245                    buf.push_str("false")
246                }
247            }
248            Self::F16(bits) => buf.push_str(&super::f16_to_f64(*bits).to_string()),
249            Self::F32(f) => buf.push_str(&f.to_string()),
250            Self::F64(f) => buf.push_str(&f.to_string()),
251            Self::I8(i) => buf.push_str(&i.to_string()),
252            Self::I16(i) => buf.push_str(&i.to_string()),
253            Self::I32(i) => buf.push_str(&i.to_string()),
254            Self::I64(i) => buf.push_str(&i.to_string()),
255            Self::U8(i) => buf.push_str(&i.to_string()),
256            Self::U16(i) => buf.push_str(&i.to_string()),
257            Self::U32(i) => buf.push_str(&i.to_string()),
258            Self::U64(i) => buf.push_str(&i.to_string()),
259            Self::Null => buf.push_str("null"),
260            Self::String(s) => s.as_str().to_json(buf),
261            Self::StringBuf(s) => s.as_str().to_json(buf),
262            Self::Bytes(vec) => vec_to_json!(buf, vec, U8),
263            Self::VecI8(vec) => vec_to_json!(buf, vec, I8),
264            Self::VecU16(vec) => vec_to_json!(buf, vec, U16),
265            Self::VecI16(vec) => vec_to_json!(buf, vec, I16),
266            Self::VecU32(vec) => vec_to_json!(buf, vec, U32),
267            Self::VecI32(vec) => vec_to_json!(buf, vec, I32),
268            Self::VecF32(vec) => vec_to_json!(buf, vec, F32),
269            Self::VecU64(vec) => vec_to_json!(buf, vec, U64),
270            Self::VecI64(vec) => vec_to_json!(buf, vec, I64),
271            Self::VecF64(vec) => vec_to_json!(buf, vec, F64),
272            Self::List(a) => {
273                buf.push('[');
274                let mut once = ZOnce::new("", ",\n");
275                a.read().iter().for_each(|item| {
276                    buf.push_str(once.take());
277                    item.to_json(buf);
278                });
279                buf.push(']');
280            }
281            Self::Map(map) => {
282                buf.push('{');
283                let mut once = ZOnce::new("", ",\n");
284                map.read().iter().for_each(|(k, v)| {
285                    buf.push_str(once.take());
286                    k.as_str().to_json(buf);
287                    buf.push_str(": ");
288                    v.to_json(buf);
289                });
290                buf.push_str("}\n");
291            }
292            Self::StructView { .. } | Self::StructOwned { .. } => {
293                buf.push('{');
294                let mut once = ZOnce::new("", ",\n");
295                self.keys().iter().for_each(|k| {
296                    buf.push_str(once.take());
297                    k.as_str().to_json(buf);
298                    buf.push_str(": ");
299                    self.get_dynamic(k).unwrap_or(Dynamic::Null).to_json(buf);
300                });
301                buf.push_str("}\n");
302            }
303            Self::Custom(value) => {
304                buf.push_str("{\"@custom\":");
305                value.custom_type_name().to_json(buf);
306                buf.push('}');
307            }
308        }
309    }
310}