Skip to main content

tachyon_json/
value.rs

1use crate::buffer::TachyonBuffer;
2use crate::tcopy;
3
4const CONTROL_ESCAPES: [&[u8]; 32] = [
5    br"\u0000", br"\u0001", br"\u0002", br"\u0003", br"\u0004", br"\u0005", br"\u0006", br"\u0007",
6    br"\b", br"\t", br"\n", br"\u000B", br"\f", br"\r", br"\u000E", br"\u000F", br"\u0010",
7    br"\u0011", br"\u0012", br"\u0013", br"\u0014", br"\u0015", br"\u0016", br"\u0017", br"\u0018",
8    br"\u0019", br"\u001A", br"\u001B", br"\u001C", br"\u001D", br"\u001E", br"\u001F",
9];
10
11#[repr(u8)]
12pub enum TachyonValue<'a> {
13    String(&'a str) = 0,
14    Number(f64) = 1,
15    Object(TachyonObject<'a>) = 2,
16    Array(&'a [TachyonValue<'a>]) = 3,
17    True = 4,
18    False = 5,
19    Null = 6,
20    Undefined = 7,
21}
22
23pub struct TachyonObject<'a> {
24    pub ptr: *const TachyonPair<'a>,
25    pub len: usize,
26}
27
28pub struct TachyonPair<'a> {
29    pub key: &'a str,
30    pub value: TachyonValue<'a>,
31}
32
33impl<'a> TachyonValue<'a> {
34    #[inline(always)]
35    pub unsafe fn encode<const N: usize>(&self, b: &mut TachyonBuffer<N>, no_escape: bool) {
36        match self {
37            TachyonValue::String(s) => {
38                if no_escape {
39                    b.write_char_fast(b'"');
40                    let src = s.as_ptr();
41                    let len = s.len();
42                    let dst = b.buf.as_mut_ptr().add(b.pos);
43                    tcopy!(len, b, dst, src);
44                    b.write_char_fast(b'"');
45                } else {
46                    b.write_char_fast(b'"');
47                    let bytes = s.as_bytes();
48                    let mut i = 0;
49
50                    while i < bytes.len() {
51                        let c = bytes[i];
52                        match c {
53                            b'"' => b.write(b"\\\""),
54                            b'\\' => b.write(b"\\\\"),
55                            0x00..=0x1F => b.write(CONTROL_ESCAPES[c as usize]),
56                            _ => b.write_char_fast(c),
57                        }
58                        i += 1;
59                    }
60                    b.write_char_fast(b'"');
61                }
62            }
63
64            TachyonValue::Number(n) => {
65                let mut buf = ryu::Buffer::new();
66                b.write_str(buf.format(*n));
67            }
68
69            TachyonValue::Object(obj) => {
70                b.write_char_fast(b'{');
71                let mut first = true;
72
73                let mut i = 0;
74                while i < obj.len {
75                    let pair = unsafe { &*obj.ptr.add(i) };
76                    i += 1;
77
78                    if let TachyonValue::Undefined = pair.value {
79                        continue;
80                    }
81
82                    if !first {
83                        b.write_char_fast(b',');
84                    }
85                    first = false;
86
87                    let key = pair.key.as_bytes();
88                    b.write_char_fast(b'"');
89
90                    let src = key.as_ptr();
91                    let len = key.len();
92                    let dst = b.buf.as_mut_ptr().add(b.pos);
93                    tcopy!(len, b, dst, src);
94
95                    b.write_char_fast(b'"');
96                    b.write_char_fast(b':');
97                    pair.value.encode::<N>(b, no_escape);
98                }
99
100                b.write_char_fast(b'}');
101            }
102
103            TachyonValue::Array(items) => {
104                b.write_char_fast(b'[');
105                let mut first = true;
106
107                for item in items.iter() {
108                    if matches!(item, TachyonValue::Undefined) {
109                        continue;
110                    }
111
112                    if !first {
113                        b.write_char_fast(b',');
114                    }
115                    first = false;
116
117                    item.encode::<N>(b, no_escape);
118                }
119
120                b.write_char_fast(b']');
121            }
122
123            TachyonValue::True => b.write_str("true"),
124            TachyonValue::False => b.write_str("false"),
125            TachyonValue::Null => b.write_str("null"),
126            TachyonValue::Undefined => b.error = true,
127        }
128    }
129}
130
131#[repr(transparent)]
132pub struct FastStr(pub *const u8);
133impl Copy for FastStr {}
134impl Clone for FastStr {
135    fn clone(&self) -> Self {
136        *self
137    }
138}
139impl FastStr {
140    #[inline(always)]
141    pub fn new(s: &'static str) -> Self {
142        let ptr = (s.as_ptr() as usize | 1) as *const u8;
143        Self(ptr)
144    }
145    #[inline(always)]
146    pub fn as_str(&self, len: usize) -> &'static str {
147        let ptr = (self.0 as usize & !1) as *const u8;
148        unsafe { std::str::from_utf8_unchecked(std::slice::from_raw_parts(ptr, len)) }
149    }
150}