protocrap 0.3.2

A small, efficient, and flexible protobuf implementation
Documentation
use core::{
    ops::{Add, AddAssign, Index, IndexMut, Sub},
    ptr::NonNull,
};

pub(crate) const SLOP_SIZE: usize = 16;

pub(crate) fn zigzag_decode(n: u64) -> i64 {
    ((n >> 1) as i64) ^ (-((n & 1) as i64))
}

pub(crate) fn zigzag_encode(n: i64) -> u64 {
    ((n as u64) << 1) ^ ((n >> 63) as u64)
}

#[derive(Clone, Copy)]
pub(crate) struct ReadCursor(pub NonNull<u8>);

#[inline(never)]
fn read_varint(ptr: ReadCursor) -> (Option<ReadCursor>, u64) {
    let mut result = 0;
    let mut extra = 0;
    for i in 0..10 {
        let b = ptr[i];
        if i == 9 && b != 1 {
            break;
        }
        result ^= (b as u64) << (7 * i);
        if b < 0x80 {
            return (Some(ptr + i + 1), result ^ extra);
        }
        extra ^= 0x80 << (7 * i);
    }
    (None, 0)
}

#[inline(never)]
fn read_tag(ptr: ReadCursor) -> (Option<ReadCursor>, u32) {
    let mut result = 0;
    let mut extra = 0;
    for i in 0..5 {
        let b = ptr[i];
        if i == 4 && (b == 0 || b > 15) {
            break;
        }
        result ^= (b as u32) << (7 * i);
        if b < 0x80 {
            return (Some(ptr + i + 1), result ^ extra);
        }
        extra ^= 0x80 << (7 * i);
    }
    (None, 0)
}

#[inline(never)]
fn read_size(ptr: ReadCursor) -> (Option<ReadCursor>, isize) {
    let mut result = 0;
    let mut extra = 0;
    for i in 0..5 {
        let b = ptr[i];
        if i == 4 && (b == 0 || b > 7) {
            break;
        }
        result ^= (b as isize) << (7 * i);
        if b < 0x80 {
            return (Some(ptr + i + 1), result ^ extra);
        }
        extra ^= 0x80 << (7 * i);
    }
    (None, 0)
}

impl ReadCursor {
    pub fn new(buffer: &[u8]) -> (Self, NonNull<u8>) {
        let ptr = ReadCursor(NonNull::from_ref(&buffer[0]));
        let end = (ptr + buffer.len() as isize).0;
        (ptr, end)
    }

    #[inline(always)]
    pub fn read_varint(&mut self) -> Option<u64> {
        let res = self[0] as u64;
        if crate::utils::likely(res < 0x80) {
            *self += 1;
            Some(res)
        } else {
            let (Some(new_ptr), value) = read_varint(*self) else {
                return None;
            };
            *self = new_ptr;
            Some(value)
        }
    }

    #[inline(always)]
    pub fn read_tag(&mut self) -> Option<u32> {
        let res = self[0] as u32;
        if crate::utils::likely(res < 0x80) {
            *self += 1;
            Some(res)
        } else {
            let (Some(new_ptr), value) = read_tag(*self) else {
                return None;
            };
            *self = new_ptr;
            Some(value)
        }
    }

    // Reads a isize varint limited to i32::MAX (used for lengths)
    #[inline(always)]
    pub fn read_size(&mut self) -> Option<isize> {
        let res = self[0] as isize;
        if crate::utils::likely(res < 0x80) {
            *self += 1;
            Some(res)
        } else {
            let (Some(new_ptr), value) = read_size(*self) else {
                return None;
            };
            *self = new_ptr;
            Some(value)
        }
    }

    #[inline(always)]
    pub fn read_unaligned<T>(&mut self) -> T {
        let value = unsafe { self.0.cast::<T>().read_unaligned() };
        *self += core::mem::size_of::<T>() as isize;
        value
    }

    #[inline(always)]
    pub fn read_slice(&mut self, len: isize) -> &[u8] {
        let p = self.0.as_ptr();
        let slice = unsafe { core::slice::from_raw_parts(p, len as usize) };
        *self += len;
        slice
    }
}

impl PartialEq<NonNull<u8>> for ReadCursor {
    #[inline(always)]
    fn eq(&self, other: &NonNull<u8>) -> bool {
        self.0.as_ptr() == other.as_ptr()
    }
}

impl PartialOrd<NonNull<u8>> for ReadCursor {
    fn partial_cmp(&self, other: &NonNull<u8>) -> Option<core::cmp::Ordering> {
        Some(self.0.cmp(other))
    }
}

impl Add<isize> for ReadCursor {
    type Output = ReadCursor;
    fn add(self, rhs: isize) -> Self::Output {
        ReadCursor(unsafe { self.0.offset(rhs) })
    }
}

impl AddAssign<isize> for ReadCursor {
    #[inline(always)]
    fn add_assign(&mut self, rhs: isize) {
        *self = *self + rhs;
    }
}

impl Sub<NonNull<u8>> for ReadCursor {
    type Output = isize;
    fn sub(self, rhs: NonNull<u8>) -> Self::Output {
        self.0.as_ptr() as isize - rhs.as_ptr() as isize
    }
}

impl Index<isize> for ReadCursor {
    type Output = u8;
    #[inline(always)]
    fn index(&self, index: isize) -> &Self::Output {
        unsafe { &*self.0.as_ptr().offset(index) }
    }
}

fn varint_size(n: u64) -> isize {
    let log2 = (n | 1).ilog2();
    ((log2 * 9 + 64 + 9) / 64) as isize
}

#[derive(Clone, Copy)]
pub(crate) struct WriteCursor(pub NonNull<u8>);

impl WriteCursor {
    pub fn new(buffer: &mut [u8]) -> (Self, NonNull<u8>) {
        let mut ptr = WriteCursor(NonNull::from_mut(&mut buffer[0]));
        let end = ptr.0;
        ptr += buffer.len() as isize;
        (ptr, end)
    }

    pub fn write_varint(&mut self, mut n: u64) {
        *self += -varint_size(n);
        let mut i = 0;
        while n >= 0x80 {
            self[i] = n as u8 | 0x80;
            n >>= 7;
            i += 1;
        }
        self[i] = n as u8;
    }

    pub fn write_unaligned<T>(&mut self, value: T) {
        *self += -(core::mem::size_of::<T>() as isize);
        unsafe {
            self.0.cast::<T>().write_unaligned(value);
        }
    }

    pub fn write_slice(&mut self, slice: &[u8]) {
        let len = slice.len();
        *self += -(len as isize);
        let p = self.0.as_ptr();
        unsafe {
            core::ptr::copy_nonoverlapping(slice.as_ptr(), p, len);
        }
    }

    pub fn write_tag(&mut self, tag: u32) {
        // TODO optimize
        self.write_varint(tag as u64);
    }
}

impl PartialEq<NonNull<u8>> for WriteCursor {
    fn eq(&self, other: &NonNull<u8>) -> bool {
        self.0.as_ptr() == other.as_ptr()
    }
}

impl PartialOrd<NonNull<u8>> for WriteCursor {
    fn partial_cmp(&self, other: &NonNull<u8>) -> Option<core::cmp::Ordering> {
        Some(self.0.cmp(other))
    }
}

impl Add<isize> for WriteCursor {
    type Output = WriteCursor;
    fn add(self, rhs: isize) -> Self::Output {
        WriteCursor(unsafe { self.0.offset(rhs) })
    }
}

impl AddAssign<isize> for WriteCursor {
    fn add_assign(&mut self, rhs: isize) {
        *self = *self + rhs;
    }
}

impl Sub<NonNull<u8>> for WriteCursor {
    type Output = isize;
    fn sub(self, rhs: NonNull<u8>) -> Self::Output {
        self.0.as_ptr() as isize - rhs.as_ptr() as isize
    }
}

impl Index<isize> for WriteCursor {
    type Output = u8;
    fn index(&self, index: isize) -> &Self::Output {
        unsafe { &*self.0.as_ptr().offset(index) }
    }
}

impl IndexMut<isize> for WriteCursor {
    fn index_mut(&mut self, index: isize) -> &mut Self::Output {
        unsafe { &mut *self.0.as_ptr().offset(index) }
    }
}

#[repr(u8)]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum FieldKind {
    Unknown,
    Varint64,
    Varint32,
    Int32,
    Varint64Zigzag,
    Varint32Zigzag,
    Bool,
    Fixed64,
    Fixed32,
    Bytes,
    String,
    Message,
    Group,
    RepeatedVarint64,
    RepeatedVarint32,
    RepeatedInt32,
    RepeatedVarint64Zigzag,
    RepeatedVarint32Zigzag,
    RepeatedBool,
    RepeatedFixed64,
    RepeatedFixed32,
    RepeatedBytes,
    RepeatedString,
    RepeatedMessage,
    RepeatedGroup,
}