Skip to main content

sark_json/
encode.rs

1use o3::buffer::Owned;
2
3pub struct Writer<'a> {
4    buf: &'a mut Owned,
5    ptr: *mut u8,
6    cap: usize,
7    len: usize,
8}
9
10impl<'a> Writer<'a> {
11    pub fn new(buf: &'a mut Owned, estimate: usize) -> Self {
12        let len = buf.len();
13        buf.reserve(estimate);
14        let cap = buf.capacity();
15        let spare = buf.spare_capacity_mut();
16        let ptr = spare.as_mut_ptr().cast::<u8>();
17        // SAFETY: spare_capacity_mut starts at base + len, so base = spare - len is in-bounds.
18        let ptr = unsafe { ptr.sub(len) };
19        Self { buf, ptr, cap, len }
20    }
21
22    #[cold]
23    fn grow(&mut self, additional: usize) {
24        // SAFETY: self.len bytes were written into buf's spare region.
25        unsafe { self.buf.set_len(self.len) };
26        self.buf.reserve(additional);
27        self.cap = self.buf.capacity();
28        let len = self.len;
29        let spare = self.buf.spare_capacity_mut();
30        // SAFETY: spare starts at base + len, so base = spare - len is in-bounds.
31        self.ptr = unsafe { spare.as_mut_ptr().cast::<u8>().sub(len) };
32    }
33
34    pub fn put(&mut self, src: &[u8]) {
35        let need = self.len + src.len();
36        if need > self.cap {
37            self.grow(src.len());
38        }
39        // SAFETY: need <= cap holds after grow, so ptr + len .. + src.len() stays in-bounds.
40        unsafe {
41            std::ptr::copy_nonoverlapping(src.as_ptr(), self.ptr.add(self.len), src.len());
42        }
43        self.len = need;
44    }
45
46    pub fn put_str(&mut self, value: &[u8]) {
47        self.put(b"\"");
48        let mut start = 0usize;
49        let mut idx = 0usize;
50        while idx < value.len() {
51            if let Some(token) = Encode::esc_token(value[idx]) {
52                if start != idx {
53                    self.put(&value[start..idx]);
54                }
55                self.put(token.as_bytes());
56                idx += 1;
57                start = idx;
58                continue;
59            }
60            idx += 1;
61        }
62        if start != value.len() {
63            self.put(&value[start..]);
64        }
65        self.put(b"\"");
66    }
67
68    pub fn put_str_plain(&mut self, value: &[u8]) {
69        self.put(b"\"");
70        self.put(value);
71        self.put(b"\"");
72    }
73
74    pub fn put_u64(&mut self, value: u64) {
75        if value == 0 {
76            self.put(b"0");
77            return;
78        }
79        let mut digits = [0u8; 20];
80        let mut idx = digits.len();
81        let mut value = value;
82        while value != 0 {
83            idx -= 1;
84            digits[idx] = b'0' + (value % 10) as u8;
85            value /= 10;
86        }
87        self.put(&digits[idx..]);
88    }
89
90    pub fn finish(self) {
91        // SAFETY: self.len bytes were written into buf's spare region.
92        unsafe { self.buf.set_len(self.len) };
93    }
94}
95
96pub struct Encode;
97
98impl Encode {
99    pub fn u64_len(mut value: u64) -> usize {
100        if value == 0 {
101            return 1;
102        }
103        let mut digits = 0usize;
104        while value != 0 {
105            digits += 1;
106            value /= 10;
107        }
108        digits
109    }
110
111    pub fn str_len(value: &[u8]) -> usize {
112        2 + Self::esc_len(value)
113    }
114
115    fn esc_len(value: &[u8]) -> usize {
116        let mut len = 0usize;
117        let mut idx = 0usize;
118        while idx < value.len() {
119            len += Self::esc_size(value[idx]);
120            idx += 1;
121        }
122        len
123    }
124
125    fn esc_size(byte: u8) -> usize {
126        match Self::esc_token(byte) {
127            Some(token) => token.len(),
128            None => 1,
129        }
130    }
131
132    fn esc_token(byte: u8) -> Option<&'static str> {
133        match byte {
134            b'"' => Some("\\\""),
135            b'\\' => Some("\\\\"),
136            b'\n' => Some("\\n"),
137            b'\r' => Some("\\r"),
138            b'\t' => Some("\\t"),
139            0x00 => Some("\\u0000"),
140            0x01 => Some("\\u0001"),
141            0x02 => Some("\\u0002"),
142            0x03 => Some("\\u0003"),
143            0x04 => Some("\\u0004"),
144            0x05 => Some("\\u0005"),
145            0x06 => Some("\\u0006"),
146            0x07 => Some("\\u0007"),
147            0x08 => Some("\\b"),
148            0x0b => Some("\\u000b"),
149            0x0c => Some("\\f"),
150            0x0e => Some("\\u000e"),
151            0x0f => Some("\\u000f"),
152            0x10 => Some("\\u0010"),
153            0x11 => Some("\\u0011"),
154            0x12 => Some("\\u0012"),
155            0x13 => Some("\\u0013"),
156            0x14 => Some("\\u0014"),
157            0x15 => Some("\\u0015"),
158            0x16 => Some("\\u0016"),
159            0x17 => Some("\\u0017"),
160            0x18 => Some("\\u0018"),
161            0x19 => Some("\\u0019"),
162            0x1a => Some("\\u001a"),
163            0x1b => Some("\\u001b"),
164            0x1c => Some("\\u001c"),
165            0x1d => Some("\\u001d"),
166            0x1e => Some("\\u001e"),
167            0x1f => Some("\\u001f"),
168            _ => None,
169        }
170    }
171}