Skip to main content

fory_core/
buffer.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18use crate::error::Error;
19use crate::meta::buffer_rw_string::read_latin1_simd;
20use byteorder::{ByteOrder, LittleEndian};
21use std::cmp::max;
22
23/// Threshold for using SIMD optimizations in string operations.
24/// For buffers smaller than this, direct copy is faster than SIMD setup overhead.
25const SIMD_THRESHOLD: usize = 128;
26
27pub struct Writer<'a> {
28    pub(crate) bf: &'a mut Vec<u8>,
29}
30impl<'a> Writer<'a> {
31    // ============ Utility methods ============
32
33    #[inline(always)]
34    pub fn from_buffer(bf: &'a mut Vec<u8>) -> Writer<'a> {
35        Writer { bf }
36    }
37
38    #[inline(always)]
39    pub fn dump(&self) -> Vec<u8> {
40        self.bf.clone()
41    }
42
43    #[inline(always)]
44    pub fn reset(&mut self) {
45        self.bf.clear();
46    }
47
48    #[inline(always)]
49    pub fn len(&self) -> usize {
50        self.bf.len()
51    }
52
53    #[inline(always)]
54    pub fn is_empty(&self) -> bool {
55        self.bf.is_empty()
56    }
57
58    #[inline(always)]
59    pub fn reserve(&mut self, additional: usize) {
60        if self.bf.capacity() - self.len() < additional {
61            self.bf.reserve(max(additional * 2, self.bf.capacity()));
62        }
63    }
64
65    #[inline(always)]
66    pub fn skip(&mut self, len: usize) {
67        self.bf.resize(self.bf.len() + len, 0);
68    }
69
70    #[inline(always)]
71    pub fn set_bytes(&mut self, offset: usize, data: &[u8]) {
72        self.bf
73            .get_mut(offset..offset + data.len())
74            .unwrap()
75            .copy_from_slice(data);
76    }
77
78    #[inline(always)]
79    pub fn write_bytes(&mut self, v: &[u8]) -> usize {
80        self.bf.extend_from_slice(v);
81        v.len()
82    }
83
84    // ============ BOOL (TypeId = 1) ============
85
86    #[inline(always)]
87    pub fn write_bool(&mut self, value: bool) {
88        self.bf.push(if value { 1 } else { 0 });
89    }
90
91    // ============ INT8 (TypeId = 2) ============
92
93    #[inline(always)]
94    pub fn write_i8(&mut self, value: i8) {
95        self.bf.push(value as u8);
96    }
97
98    // ============ INT16 (TypeId = 3) ============
99
100    #[inline(always)]
101    pub fn write_i16(&mut self, value: i16) {
102        self.write_u16(value as u16);
103    }
104
105    // ============ INT32 (TypeId = 4) ============
106
107    #[inline(always)]
108    pub fn write_i32(&mut self, value: i32) {
109        self.write_u32(value as u32);
110    }
111
112    // ============ VARINT32 (TypeId = 5) ============
113
114    #[inline(always)]
115    pub fn write_varint32(&mut self, value: i32) {
116        let zigzag = ((value as i64) << 1) ^ ((value as i64) >> 31);
117        self._write_var_uint32(zigzag as u32)
118    }
119
120    // ============ INT64 (TypeId = 6) ============
121
122    #[inline(always)]
123    pub fn write_i64(&mut self, value: i64) {
124        self.write_u64(value as u64);
125    }
126
127    // ============ VARINT64 (TypeId = 7) ============
128
129    #[inline(always)]
130    pub fn write_varint64(&mut self, value: i64) {
131        let zigzag = ((value << 1) ^ (value >> 63)) as u64;
132        self._write_var_uint64(zigzag);
133    }
134
135    // ============ TAGGED_INT64 (TypeId = 8) ============
136
137    /// Write signed long using fory Tagged(Small long as int) encoding.
138    /// If value is in [0xc0000000, 0x3fffffff] (i.e., [-1073741824, 1073741823]),
139    /// encode as 4 bytes: `((value as i32) << 1)`.
140    /// Otherwise write as 9 bytes: `0b1 | little-endian 8 bytes i64`.
141    #[inline(always)]
142    pub fn write_tagged_i64(&mut self, value: i64) {
143        const HALF_MIN_INT_VALUE: i64 = i32::MIN as i64 / 2; // -1073741824
144        const HALF_MAX_INT_VALUE: i64 = i32::MAX as i64 / 2; // 1073741823
145        if (HALF_MIN_INT_VALUE..=HALF_MAX_INT_VALUE).contains(&value) {
146            // Fits in 31 bits (with sign), encode as 4 bytes with bit 0 = 0
147            let v = (value as i32) << 1;
148            self.write_i32(v);
149        } else {
150            // Write flag byte (0b1) followed by 8-byte i64
151            self.bf.push(0b1);
152            self.write_i64(value);
153        }
154    }
155
156    // ============ UINT8 (TypeId = 9) ============
157
158    #[inline(always)]
159    pub fn write_u8(&mut self, value: u8) {
160        self.bf.push(value);
161    }
162
163    // ============ UINT16 (TypeId = 10) ============
164
165    #[inline(always)]
166    pub fn write_u16(&mut self, value: u16) {
167        #[cfg(target_endian = "little")]
168        {
169            let bytes = unsafe { &*(&value as *const u16 as *const [u8; 2]) };
170            self.bf.extend_from_slice(bytes);
171        }
172        #[cfg(target_endian = "big")]
173        {
174            self.bf.extend_from_slice(&value.to_le_bytes());
175        }
176    }
177
178    // ============ UINT32 (TypeId = 11) ============
179
180    #[inline(always)]
181    pub fn write_u32(&mut self, value: u32) {
182        #[cfg(target_endian = "little")]
183        {
184            let bytes = unsafe { &*(&value as *const u32 as *const [u8; 4]) };
185            self.bf.extend_from_slice(bytes);
186        }
187        #[cfg(target_endian = "big")]
188        {
189            self.bf.extend_from_slice(&value.to_le_bytes());
190        }
191    }
192
193    // ============ VAR_UINT32 (TypeId = 12) ============
194
195    #[inline(always)]
196    pub fn write_var_uint32(&mut self, value: u32) {
197        self._write_var_uint32(value)
198    }
199
200    #[inline(always)]
201    fn _write_var_uint32(&mut self, value: u32) {
202        if value < 0x80 {
203            self.bf.push(value as u8);
204        } else if value < 0x4000 {
205            // 2 bytes
206            let u1 = ((value as u8) & 0x7F) | 0x80;
207            let u2 = (value >> 7) as u8;
208            self.write_u16(((u2 as u16) << 8) | u1 as u16);
209        } else if value < 0x200000 {
210            // 3 bytes
211            let u1 = ((value as u8) & 0x7F) | 0x80;
212            let u2 = (((value >> 7) as u8) & 0x7F) | 0x80;
213            let u3 = (value >> 14) as u8;
214            self.write_u16(((u2 as u16) << 8) | u1 as u16);
215            self.bf.push(u3);
216        } else if value < 0x10000000 {
217            // 4 bytes
218            let u1 = ((value as u8) & 0x7F) | 0x80;
219            let u2 = (((value >> 7) as u8) & 0x7F) | 0x80;
220            let u3 = (((value >> 14) as u8) & 0x7F) | 0x80;
221            let u4 = (value >> 21) as u8;
222            self.write_u32(
223                ((u4 as u32) << 24) | ((u3 as u32) << 16) | ((u2 as u32) << 8) | u1 as u32,
224            );
225        } else {
226            // 5 bytes
227            let u1 = ((value as u8) & 0x7F) | 0x80;
228            let u2 = (((value >> 7) as u8) & 0x7F) | 0x80;
229            let u3 = (((value >> 14) as u8) & 0x7F) | 0x80;
230            let u4 = (((value >> 21) as u8) & 0x7F) | 0x80;
231            let u5 = (value >> 28) as u8;
232            self.write_u32(
233                ((u4 as u32) << 24) | ((u3 as u32) << 16) | ((u2 as u32) << 8) | u1 as u32,
234            );
235            self.bf.push(u5);
236        }
237    }
238
239    // ============ UINT64 (TypeId = 13) ============
240
241    #[inline(always)]
242    pub fn write_u64(&mut self, value: u64) {
243        #[cfg(target_endian = "little")]
244        {
245            let bytes = unsafe { &*(&value as *const u64 as *const [u8; 8]) };
246            self.bf.extend_from_slice(bytes);
247        }
248        #[cfg(target_endian = "big")]
249        {
250            self.bf.extend_from_slice(&value.to_le_bytes());
251        }
252    }
253
254    // ============ VAR_UINT64 (TypeId = 14) ============
255
256    #[inline(always)]
257    pub fn write_var_uint64(&mut self, value: u64) {
258        self._write_var_uint64(value);
259    }
260
261    #[inline(always)]
262    fn _write_var_uint64(&mut self, value: u64) {
263        if value < 0x80 {
264            self.bf.push(value as u8);
265        } else if value < 0x4000 {
266            let u1 = ((value as u8) & 0x7F) | 0x80;
267            let u2 = (value >> 7) as u8;
268            self.write_u16(((u2 as u16) << 8) | u1 as u16);
269        } else if value < 0x200000 {
270            let u1 = ((value as u8) & 0x7F) | 0x80;
271            let u2 = (((value >> 7) as u8) & 0x7F) | 0x80;
272            let u3 = (value >> 14) as u8;
273            self.write_u16(((u2 as u16) << 8) | u1 as u16);
274            self.bf.push(u3);
275        } else if value < 0x10000000 {
276            let u1 = ((value as u8) & 0x7F) | 0x80;
277            let u2 = (((value >> 7) as u8) & 0x7F) | 0x80;
278            let u3 = (((value >> 14) as u8) & 0x7F) | 0x80;
279            let u4 = (value >> 21) as u8;
280            self.write_u32(
281                ((u4 as u32) << 24) | ((u3 as u32) << 16) | ((u2 as u32) << 8) | u1 as u32,
282            );
283        } else if value < 0x800000000 {
284            let u1 = ((value as u8) & 0x7F) | 0x80;
285            let u2 = (((value >> 7) as u8) & 0x7F) | 0x80;
286            let u3 = (((value >> 14) as u8) & 0x7F) | 0x80;
287            let u4 = (((value >> 21) as u8) & 0x7F) | 0x80;
288            let u5 = (value >> 28) as u8;
289            self.write_u32(
290                ((u4 as u32) << 24) | ((u3 as u32) << 16) | ((u2 as u32) << 8) | u1 as u32,
291            );
292            self.bf.push(u5);
293        } else if value < 0x40000000000 {
294            let u1 = ((value as u8) & 0x7F) | 0x80;
295            let u2 = (((value >> 7) as u8) & 0x7F) | 0x80;
296            let u3 = (((value >> 14) as u8) & 0x7F) | 0x80;
297            let u4 = (((value >> 21) as u8) & 0x7F) | 0x80;
298            let u5 = (((value >> 28) as u8) & 0x7F) | 0x80;
299            let u6 = (value >> 35) as u8;
300            self.write_u32(
301                ((u4 as u32) << 24) | ((u3 as u32) << 16) | ((u2 as u32) << 8) | u1 as u32,
302            );
303            self.write_u16(((u6 as u16) << 8) | u5 as u16);
304        } else if value < 0x2000000000000 {
305            let u1 = ((value as u8) & 0x7F) | 0x80;
306            let u2 = (((value >> 7) as u8) & 0x7F) | 0x80;
307            let u3 = (((value >> 14) as u8) & 0x7F) | 0x80;
308            let u4 = (((value >> 21) as u8) & 0x7F) | 0x80;
309            let u5 = (((value >> 28) as u8) & 0x7F) | 0x80;
310            let u6 = (((value >> 35) as u8) & 0x7F) | 0x80;
311            let u7 = (value >> 42) as u8;
312            self.write_u32(
313                ((u4 as u32) << 24) | ((u3 as u32) << 16) | ((u2 as u32) << 8) | u1 as u32,
314            );
315            self.write_u16(((u6 as u16) << 8) | u5 as u16);
316            self.bf.push(u7);
317        } else if value < 0x100000000000000 {
318            let u1 = ((value as u8) & 0x7F) | 0x80;
319            let u2 = (((value >> 7) as u8) & 0x7F) | 0x80;
320            let u3 = (((value >> 14) as u8) & 0x7F) | 0x80;
321            let u4 = (((value >> 21) as u8) & 0x7F) | 0x80;
322            let u5 = (((value >> 28) as u8) & 0x7F) | 0x80;
323            let u6 = (((value >> 35) as u8) & 0x7F) | 0x80;
324            let u7 = (((value >> 42) as u8) & 0x7F) | 0x80;
325            let u8 = (value >> 49) as u8;
326            self.write_u64(
327                (u8 as u64) << 56
328                    | (u7 as u64) << 48
329                    | (u6 as u64) << 40
330                    | (u5 as u64) << 32
331                    | (u4 as u64) << 24
332                    | (u3 as u64) << 16
333                    | (u2 as u64) << 8
334                    | (u1 as u64),
335            );
336        } else {
337            let u1 = ((value as u8) & 0x7F) | 0x80;
338            let u2 = (((value >> 7) as u8) & 0x7F) | 0x80;
339            let u3 = (((value >> 14) as u8) & 0x7F) | 0x80;
340            let u4 = (((value >> 21) as u8) & 0x7F) | 0x80;
341            let u5 = (((value >> 28) as u8) & 0x7F) | 0x80;
342            let u6 = (((value >> 35) as u8) & 0x7F) | 0x80;
343            let u7 = (((value >> 42) as u8) & 0x7F) | 0x80;
344            let u8 = (((value >> 49) as u8) & 0x7F) | 0x80;
345            let u9 = (value >> 56) as u8;
346            self.write_u64(
347                (u8 as u64) << 56
348                    | (u7 as u64) << 48
349                    | (u6 as u64) << 40
350                    | (u5 as u64) << 32
351                    | (u4 as u64) << 24
352                    | (u3 as u64) << 16
353                    | (u2 as u64) << 8
354                    | (u1 as u64),
355            );
356            self.bf.push(u9);
357        }
358    }
359
360    // ============ TAGGED_UINT64 (TypeId = 15) ============
361
362    /// Write unsigned long using fory Tagged(Small long as int) encoding.
363    /// If value is in [0, 0x7fffffff], encode as 4 bytes: `((value as u32) << 1)`.
364    /// Otherwise write as 9 bytes: `0b1 | little-endian 8 bytes u64`.
365    #[inline(always)]
366    pub fn write_tagged_u64(&mut self, value: u64) {
367        if value <= i32::MAX as u64 {
368            // Fits in 31 bits, encode as 4 bytes with bit 0 = 0
369            let v = (value as u32) << 1;
370            self.write_u32(v);
371        } else {
372            // Write flag byte (0b1) followed by 8-byte u64
373            self.bf.push(0b1);
374            self.write_u64(value);
375        }
376    }
377
378    // ============ FLOAT32 (TypeId = 17) ============
379
380    #[inline(always)]
381    pub fn write_f32(&mut self, value: f32) {
382        #[cfg(target_endian = "little")]
383        {
384            let bytes = unsafe { &*(&value as *const f32 as *const [u8; 4]) };
385            self.bf.extend_from_slice(bytes);
386        }
387        #[cfg(target_endian = "big")]
388        {
389            self.bf.extend_from_slice(&value.to_bits().to_le_bytes());
390        }
391    }
392
393    // ============ FLOAT64 (TypeId = 18) ============
394
395    #[inline(always)]
396    pub fn write_f64(&mut self, value: f64) {
397        #[cfg(target_endian = "little")]
398        {
399            let bytes = unsafe { &*(&value as *const f64 as *const [u8; 8]) };
400            self.bf.extend_from_slice(bytes);
401        }
402        #[cfg(target_endian = "big")]
403        {
404            self.bf.extend_from_slice(&value.to_bits().to_le_bytes());
405        }
406    }
407
408    // ============ STRING (TypeId = 19) ============
409
410    #[inline(always)]
411    pub fn write_utf8_string(&mut self, s: &str) {
412        let bytes = s.as_bytes();
413        let len = bytes.len();
414        self.bf.reserve(len);
415        self.bf.extend_from_slice(bytes);
416    }
417
418    // ============ Rust-specific types (i128, u128, isize, usize) ============
419
420    #[inline(always)]
421    pub fn write_i128(&mut self, value: i128) {
422        self.write_u128(value as u128);
423    }
424
425    #[inline(always)]
426    pub fn write_u128(&mut self, value: u128) {
427        #[cfg(target_endian = "little")]
428        {
429            let bytes = unsafe { &*(&value as *const u128 as *const [u8; 16]) };
430            self.bf.extend_from_slice(bytes);
431        }
432        #[cfg(target_endian = "big")]
433        {
434            self.bf.extend_from_slice(&value.to_le_bytes());
435        }
436    }
437
438    #[inline(always)]
439    pub fn write_isize(&mut self, value: isize) {
440        const SIZE: usize = std::mem::size_of::<isize>();
441        match SIZE {
442            2 => self.write_i16(value as i16),
443            4 => self.write_varint32(value as i32),
444            8 => self.write_varint64(value as i64),
445            _ => unreachable!("unsupported isize size"),
446        }
447    }
448
449    #[inline(always)]
450    pub fn write_usize(&mut self, value: usize) {
451        const SIZE: usize = std::mem::size_of::<usize>();
452        match SIZE {
453            2 => self.write_u16(value as u16),
454            4 => self.write_var_uint32(value as u32),
455            8 => self.write_var_uint64(value as u64),
456            _ => unreachable!("unsupported usize size"),
457        }
458    }
459
460    // ============ Other helper methods ============
461
462    #[inline(always)]
463    pub fn write_var_uint36_small(&mut self, value: u64) {
464        assert!(value < (1u64 << 36), "value too large for 36-bit varint");
465        if value < 0x80 {
466            self.bf.push(value as u8);
467        } else if value < 0x4000 {
468            let b0 = ((value & 0x7F) as u8) | 0x80;
469            let b1 = (value >> 7) as u8;
470            let combined = ((b1 as u16) << 8) | (b0 as u16);
471            self.write_u16(combined);
472        } else if value < 0x200000 {
473            let b0 = (value & 0x7F) | 0x80;
474            let b1 = ((value >> 7) & 0x7F) | 0x80;
475            let b2 = value >> 14;
476            let combined = b0 | (b1 << 8) | (b2 << 16);
477            self.write_u32(combined as u32);
478        } else if value < 0x10000000 {
479            let b0 = (value & 0x7F) | 0x80;
480            let b1 = ((value >> 7) & 0x7F) | 0x80;
481            let b2 = ((value >> 14) & 0x7F) | 0x80;
482            let b3 = value >> 21;
483            let combined = b0 | (b1 << 8) | (b2 << 16) | (b3 << 24);
484            self.write_u32(combined as u32);
485        } else {
486            let b0 = (value & 0x7F) | 0x80;
487            let b1 = ((value >> 7) & 0x7F) | 0x80;
488            let b2 = ((value >> 14) & 0x7F) | 0x80;
489            let b3 = ((value >> 21) & 0x7F) | 0x80;
490            let b4 = value >> 28;
491            let combined = b0 | (b1 << 8) | (b2 << 16) | (b3 << 24) | (b4 << 32);
492            self.write_u64(combined);
493        }
494    }
495}
496
497#[derive(Default)]
498#[allow(clippy::needless_lifetimes)]
499pub struct Reader<'a> {
500    pub(crate) bf: &'a [u8],
501    pub(crate) cursor: usize,
502}
503
504#[allow(clippy::needless_lifetimes)]
505impl<'a> Reader<'a> {
506    // ============ Utility methods ============
507
508    #[inline(always)]
509    pub fn new(bf: &[u8]) -> Reader<'_> {
510        Reader { bf, cursor: 0 }
511    }
512
513    #[inline(always)]
514    pub(crate) fn move_next(&mut self, additional: usize) {
515        self.cursor += additional;
516    }
517
518    #[inline(always)]
519    pub(crate) fn move_back(&mut self, additional: usize) {
520        self.cursor -= additional;
521    }
522
523    #[inline(always)]
524    pub fn sub_slice(&self, start: usize, end: usize) -> Result<&[u8], Error> {
525        // Allow start == bf.len() when end == bf.len() to support empty slices at buffer end
526        if start > self.bf.len() || end > self.bf.len() || end < start {
527            Err(Error::buffer_out_of_bound(
528                start,
529                self.bf.len(),
530                self.bf.len(),
531            ))
532        } else {
533            Ok(&self.bf[start..end])
534        }
535    }
536
537    #[inline(always)]
538    pub fn slice_after_cursor(&self) -> &[u8] {
539        &self.bf[self.cursor..]
540    }
541
542    #[inline(always)]
543    pub fn get_cursor(&self) -> usize {
544        self.cursor
545    }
546
547    #[inline(always)]
548    fn value_at(&self, index: usize) -> Result<u8, Error> {
549        match self.bf.get(index) {
550            None => Err(Error::buffer_out_of_bound(
551                index,
552                self.bf.len(),
553                self.bf.len(),
554            )),
555            Some(v) => Ok(*v),
556        }
557    }
558
559    #[inline(always)]
560    fn check_bound(&self, n: usize) -> Result<(), Error> {
561        if self.cursor + n > self.bf.len() {
562            Err(Error::buffer_out_of_bound(self.cursor, n, self.bf.len()))
563        } else {
564            Ok(())
565        }
566    }
567
568    #[inline(always)]
569    fn read_u8_uncheck(&mut self) -> u8 {
570        let result = unsafe { self.bf.get_unchecked(self.cursor) };
571        self.move_next(1);
572        *result
573    }
574
575    #[inline(always)]
576    pub fn skip(&mut self, len: usize) -> Result<(), Error> {
577        self.check_bound(len)?;
578        self.move_next(len);
579        Ok(())
580    }
581
582    #[inline(always)]
583    pub fn read_bytes(&mut self, len: usize) -> Result<&[u8], Error> {
584        self.check_bound(len)?;
585        let result = &self.bf[self.cursor..self.cursor + len];
586        self.move_next(len);
587        Ok(result)
588    }
589
590    #[inline(always)]
591    pub fn reset_cursor_to_here(&self) -> impl FnOnce(&mut Self) {
592        let raw_cursor = self.cursor;
593        move |this: &mut Self| {
594            this.cursor = raw_cursor;
595        }
596    }
597
598    pub fn set_cursor(&mut self, cursor: usize) {
599        self.cursor = cursor;
600    }
601
602    // ============ BOOL (TypeId = 1) ============
603
604    #[inline(always)]
605    pub fn read_bool(&mut self) -> Result<bool, Error> {
606        Ok(self.read_u8()? != 0)
607    }
608
609    // ============ INT8 (TypeId = 2) ============
610
611    #[inline(always)]
612    pub fn read_i8(&mut self) -> Result<i8, Error> {
613        Ok(self.read_u8()? as i8)
614    }
615
616    // ============ INT16 (TypeId = 3) ============
617
618    #[inline(always)]
619    pub fn read_i16(&mut self) -> Result<i16, Error> {
620        Ok(self.read_u16()? as i16)
621    }
622
623    // ============ INT32 (TypeId = 4) ============
624
625    #[inline(always)]
626    pub fn read_i32(&mut self) -> Result<i32, Error> {
627        Ok(self.read_u32()? as i32)
628    }
629
630    // ============ VARINT32 (TypeId = 5) ============
631
632    #[inline(always)]
633    pub fn read_varint32(&mut self) -> Result<i32, Error> {
634        let encoded = self.read_varuint32()?;
635        Ok(((encoded >> 1) as i32) ^ -((encoded & 1) as i32))
636    }
637
638    // ============ INT64 (TypeId = 6) ============
639
640    #[inline(always)]
641    pub fn read_i64(&mut self) -> Result<i64, Error> {
642        Ok(self.read_u64()? as i64)
643    }
644
645    // ============ VARINT64 (TypeId = 7) ============
646
647    #[inline(always)]
648    pub fn read_varint64(&mut self) -> Result<i64, Error> {
649        let encoded = self.read_varuint64()?;
650        Ok(((encoded >> 1) as i64) ^ -((encoded & 1) as i64))
651    }
652
653    // ============ TAGGED_INT64 (TypeId = 8) ============
654
655    /// Read signed fory Tagged(Small long as int) encoded i64.
656    /// If bit 0 of the first 4 bytes is 0, return the value >> 1 (arithmetic shift).
657    /// Otherwise, skip the flag byte and read 8 bytes as i64.
658    #[inline(always)]
659    pub fn read_tagged_i64(&mut self) -> Result<i64, Error> {
660        self.check_bound(4)?;
661        let i = LittleEndian::read_i32(&self.bf[self.cursor..]);
662        if (i & 0b1) != 0b1 {
663            // Bit 0 is 0, small value encoded in 4 bytes
664            self.cursor += 4;
665            Ok((i >> 1) as i64) // arithmetic right shift preserves sign
666        } else {
667            // Bit 0 is 1, big value: skip flag byte and read 8 bytes
668            self.check_bound(9)?;
669            self.cursor += 1;
670            let value = LittleEndian::read_i64(&self.bf[self.cursor..]);
671            self.cursor += 8;
672            Ok(value)
673        }
674    }
675
676    // ============ UINT8 (TypeId = 9) ============
677
678    #[inline(always)]
679    pub fn peek_u8(&mut self) -> Result<u8, Error> {
680        let result = self.value_at(self.cursor)?;
681        Ok(result)
682    }
683
684    #[inline(always)]
685    pub fn read_u8(&mut self) -> Result<u8, Error> {
686        let result = self.value_at(self.cursor)?;
687        self.move_next(1);
688        Ok(result)
689    }
690
691    // ============ UINT16 (TypeId = 10) ============
692
693    #[inline(always)]
694    pub fn read_u16(&mut self) -> Result<u16, Error> {
695        let slice = self.slice_after_cursor();
696        let result = LittleEndian::read_u16(slice);
697        self.cursor += 2;
698        Ok(result)
699    }
700
701    // ============ UINT32 (TypeId = 11) ============
702
703    #[inline(always)]
704    pub fn read_u32(&mut self) -> Result<u32, Error> {
705        let slice = self.slice_after_cursor();
706        let result = LittleEndian::read_u32(slice);
707        self.cursor += 4;
708        Ok(result)
709    }
710
711    // ============ VAR_UINT32 (TypeId = 12) ============
712
713    #[inline(always)]
714    pub fn read_varuint32(&mut self) -> Result<u32, Error> {
715        let b0 = self.value_at(self.cursor)? as u32;
716        if b0 < 0x80 {
717            self.move_next(1);
718            return Ok(b0);
719        }
720
721        let b1 = self.value_at(self.cursor + 1)? as u32;
722        let mut encoded = (b0 & 0x7F) | ((b1 & 0x7F) << 7);
723        if b1 < 0x80 {
724            self.move_next(2);
725            return Ok(encoded);
726        }
727
728        let b2 = self.value_at(self.cursor + 2)? as u32;
729        encoded |= (b2 & 0x7F) << 14;
730        if b2 < 0x80 {
731            self.move_next(3);
732            return Ok(encoded);
733        }
734
735        let b3 = self.value_at(self.cursor + 3)? as u32;
736        encoded |= (b3 & 0x7F) << 21;
737        if b3 < 0x80 {
738            self.move_next(4);
739            return Ok(encoded);
740        }
741
742        let b4 = self.value_at(self.cursor + 4)? as u32;
743        encoded |= b4 << 28;
744        self.move_next(5);
745        Ok(encoded)
746    }
747
748    // ============ UINT64 (TypeId = 13) ============
749
750    #[inline(always)]
751    pub fn read_u64(&mut self) -> Result<u64, Error> {
752        let slice = self.slice_after_cursor();
753        let result = LittleEndian::read_u64(slice);
754        self.cursor += 8;
755        Ok(result)
756    }
757
758    // ============ VAR_UINT64 (TypeId = 14) ============
759
760    #[inline(always)]
761    pub fn read_varuint64(&mut self) -> Result<u64, Error> {
762        let b0 = self.value_at(self.cursor)? as u64;
763        if b0 < 0x80 {
764            self.move_next(1);
765            return Ok(b0);
766        }
767
768        let b1 = self.value_at(self.cursor + 1)? as u64;
769        let mut result = (b0 & 0x7F) | ((b1 & 0x7F) << 7);
770        if b1 < 0x80 {
771            self.move_next(2);
772            return Ok(result);
773        }
774
775        let b2 = self.value_at(self.cursor + 2)? as u64;
776        result |= (b2 & 0x7F) << 14;
777        if b2 < 0x80 {
778            self.move_next(3);
779            return Ok(result);
780        }
781
782        let b3 = self.value_at(self.cursor + 3)? as u64;
783        result |= (b3 & 0x7F) << 21;
784        if b3 < 0x80 {
785            self.move_next(4);
786            return Ok(result);
787        }
788
789        let b4 = self.value_at(self.cursor + 4)? as u64;
790        result |= (b4 & 0x7F) << 28;
791        if b4 < 0x80 {
792            self.move_next(5);
793            return Ok(result);
794        }
795
796        let b5 = self.value_at(self.cursor + 5)? as u64;
797        result |= (b5 & 0x7F) << 35;
798        if b5 < 0x80 {
799            self.move_next(6);
800            return Ok(result);
801        }
802
803        let b6 = self.value_at(self.cursor + 6)? as u64;
804        result |= (b6 & 0x7F) << 42;
805        if b6 < 0x80 {
806            self.move_next(7);
807            return Ok(result);
808        }
809
810        let b7 = self.value_at(self.cursor + 7)? as u64;
811        result |= (b7 & 0x7F) << 49;
812        if b7 < 0x80 {
813            self.move_next(8);
814            return Ok(result);
815        }
816
817        let b8 = self.value_at(self.cursor + 8)? as u64;
818        result |= (b8 & 0xFF) << 56;
819        self.move_next(9);
820        Ok(result)
821    }
822
823    // ============ TAGGED_UINT64 (TypeId = 15) ============
824
825    /// Read unsigned fory Tagged(Small long as int) encoded u64.
826    /// If bit 0 of the first 4 bytes is 0, return the value >> 1.
827    /// Otherwise, skip the flag byte and read 8 bytes as u64.
828    #[inline(always)]
829    pub fn read_tagged_u64(&mut self) -> Result<u64, Error> {
830        self.check_bound(4)?;
831        let i = LittleEndian::read_u32(&self.bf[self.cursor..]);
832        if (i & 0b1) != 0b1 {
833            // Bit 0 is 0, small value encoded in 4 bytes
834            self.cursor += 4;
835            Ok((i >> 1) as u64)
836        } else {
837            // Bit 0 is 1, big value: skip flag byte and read 8 bytes
838            self.check_bound(9)?;
839            self.cursor += 1;
840            let value = LittleEndian::read_u64(&self.bf[self.cursor..]);
841            self.cursor += 8;
842            Ok(value)
843        }
844    }
845
846    // ============ FLOAT32 (TypeId = 17) ============
847
848    #[inline(always)]
849    pub fn read_f32(&mut self) -> Result<f32, Error> {
850        let slice = self.slice_after_cursor();
851        let result = LittleEndian::read_f32(slice);
852        self.cursor += 4;
853        Ok(result)
854    }
855
856    // ============ FLOAT64 (TypeId = 18) ============
857
858    #[inline(always)]
859    pub fn read_f64(&mut self) -> Result<f64, Error> {
860        let slice = self.slice_after_cursor();
861        let result = LittleEndian::read_f64(slice);
862        self.cursor += 8;
863        Ok(result)
864    }
865
866    // ============ STRING (TypeId = 19) ============
867
868    #[inline(always)]
869    pub fn read_latin1_string(&mut self, len: usize) -> Result<String, Error> {
870        self.check_bound(len)?;
871        if len < SIMD_THRESHOLD {
872            // Fast path for small buffers
873            unsafe {
874                let src = self.sub_slice(self.cursor, self.cursor + len)?;
875
876                // Check if all bytes are ASCII (< 0x80)
877                let is_ascii = src.iter().all(|&b| b < 0x80);
878
879                if is_ascii {
880                    // ASCII fast path: Latin1 == UTF-8, direct copy
881                    let mut vec = Vec::with_capacity(len);
882                    let dst = vec.as_mut_ptr();
883                    std::ptr::copy_nonoverlapping(src.as_ptr(), dst, len);
884                    vec.set_len(len);
885                    self.move_next(len);
886                    Ok(String::from_utf8_unchecked(vec))
887                } else {
888                    // Contains Latin1 bytes (0x80-0xFF): must convert to UTF-8
889                    let mut out: Vec<u8> = Vec::with_capacity(len * 2);
890                    let out_ptr = out.as_mut_ptr();
891                    let mut out_len = 0;
892
893                    for &b in src {
894                        if b < 0x80 {
895                            *out_ptr.add(out_len) = b;
896                            out_len += 1;
897                        } else {
898                            // Latin1 -> UTF-8 encoding
899                            *out_ptr.add(out_len) = 0xC0 | (b >> 6);
900                            *out_ptr.add(out_len + 1) = 0x80 | (b & 0x3F);
901                            out_len += 2;
902                        }
903                    }
904
905                    out.set_len(out_len);
906                    self.move_next(len);
907                    Ok(String::from_utf8_unchecked(out))
908                }
909            }
910        } else {
911            // Use SIMD for larger strings where the overhead is amortized
912            read_latin1_simd(self, len)
913        }
914    }
915
916    #[inline(always)]
917    pub fn read_utf8_string(&mut self, len: usize) -> Result<String, Error> {
918        self.check_bound(len)?;
919        // don't use simd for memory copy, copy_non_overlapping is faster
920        unsafe {
921            let mut vec = Vec::with_capacity(len);
922            let src = self.bf.as_ptr().add(self.cursor);
923            let dst = vec.as_mut_ptr();
924            // Use fastest possible copy - copy_nonoverlapping compiles to memcpy
925            std::ptr::copy_nonoverlapping(src, dst, len);
926            vec.set_len(len);
927            self.move_next(len);
928            // SAFETY: Assuming valid UTF-8 bytes (responsibility of serialization protocol)
929            Ok(String::from_utf8_unchecked(vec))
930        }
931    }
932
933    #[inline(always)]
934    pub fn read_utf16_string(&mut self, len: usize) -> Result<String, Error> {
935        self.check_bound(len)?;
936        let slice = self.sub_slice(self.cursor, self.cursor + len)?;
937        let units: Vec<u16> = slice
938            .chunks_exact(2)
939            .map(|c| u16::from_le_bytes([c[0], c[1]]))
940            .collect();
941        self.move_next(len);
942        Ok(String::from_utf16_lossy(&units))
943    }
944
945    // ============ Rust-specific types (i128, u128, isize, usize) ============
946
947    #[inline(always)]
948    pub fn read_i128(&mut self) -> Result<i128, Error> {
949        Ok(self.read_u128()? as i128)
950    }
951
952    #[inline(always)]
953    pub fn read_u128(&mut self) -> Result<u128, Error> {
954        let slice = self.slice_after_cursor();
955        let result = LittleEndian::read_u128(slice);
956        self.cursor += 16;
957        Ok(result)
958    }
959
960    #[inline(always)]
961    pub fn read_isize(&mut self) -> Result<isize, Error> {
962        const SIZE: usize = std::mem::size_of::<isize>();
963        match SIZE {
964            2 => Ok(self.read_i16()? as isize),
965            4 => Ok(self.read_varint32()? as isize),
966            8 => Ok(self.read_varint64()? as isize),
967            _ => unreachable!("unsupported isize size"),
968        }
969    }
970
971    #[inline(always)]
972    pub fn read_usize(&mut self) -> Result<usize, Error> {
973        const SIZE: usize = std::mem::size_of::<usize>();
974        match SIZE {
975            2 => Ok(self.read_u16()? as usize),
976            4 => Ok(self.read_varuint32()? as usize),
977            8 => Ok(self.read_varuint64()? as usize),
978            _ => unreachable!("unsupported usize size"),
979        }
980    }
981
982    // ============ Other helper methods ============
983
984    #[inline(always)]
985    pub fn read_varuint36small(&mut self) -> Result<u64, Error> {
986        let start = self.cursor;
987        let slice = self.slice_after_cursor();
988
989        if slice.len() >= 8 {
990            // here already check bound
991            let bulk = self.read_u64()?;
992            let mut result = bulk & 0x7F;
993            let mut read_idx = start;
994
995            if (bulk & 0x80) != 0 {
996                read_idx += 1;
997                result |= (bulk >> 1) & 0x3F80;
998                if (bulk & 0x8000) != 0 {
999                    read_idx += 1;
1000                    result |= (bulk >> 2) & 0x1FC000;
1001                    if (bulk & 0x800000) != 0 {
1002                        read_idx += 1;
1003                        result |= (bulk >> 3) & 0xFE00000;
1004                        if (bulk & 0x80000000) != 0 {
1005                            read_idx += 1;
1006                            result |= (bulk >> 4) & 0xFF0000000;
1007                        }
1008                    }
1009                }
1010            }
1011            self.cursor = read_idx + 1;
1012            return Ok(result);
1013        }
1014
1015        let mut result = 0u64;
1016        let mut shift = 0;
1017        while self.cursor < self.bf.len() {
1018            let b = self.read_u8_uncheck();
1019            result |= ((b & 0x7F) as u64) << shift;
1020            if (b & 0x80) == 0 {
1021                break;
1022            }
1023            shift += 7;
1024            if shift >= 36 {
1025                return Err(Error::encode_error("varuint36small overflow"));
1026            }
1027        }
1028        Ok(result)
1029    }
1030}
1031
1032#[allow(clippy::needless_lifetimes)]
1033unsafe impl<'a> Send for Reader<'a> {}
1034#[allow(clippy::needless_lifetimes)]
1035unsafe impl<'a> Sync for Reader<'a> {}