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}