use alloc::vec::Vec;
use crate::error::{Error, Result};
pub(crate) fn write_varint(buf: &mut Vec<u8>, mut value: u64) {
loop {
let byte = (value & 0x7F) as u8;
value >>= 7;
if value == 0 {
buf.push(byte);
break;
}
buf.push(byte | 0x80);
}
}
pub(crate) fn read_varint(input: &[u8], pos: usize) -> Result<(u64, usize)> {
let mut value: u64 = 0;
let mut shift = 0u32;
let mut i = pos;
loop {
let byte = *input
.get(i)
.ok_or_else(|| Error::custom("postcard: truncated varint"))?;
i += 1;
let payload = (byte & 0x7F) as u64;
if shift >= 64 || (shift == 63 && payload > 1) {
return Err(Error::custom("postcard: varint overflow"));
}
value |= payload << shift;
if byte & 0x80 == 0 {
if shift > 0 && payload == 0 {
return Err(Error::custom("postcard: non-canonical overlong varint"));
}
return Ok((value, i));
}
shift += 7;
if shift >= 70 {
return Err(Error::custom("postcard: varint too long"));
}
}
}
pub(crate) fn patch_prefix(buf: &mut Vec<u8>, start: usize, header: &[u8]) {
debug_assert!(start < buf.len(), "prefix start out of range");
let extra = header.len().saturating_sub(1);
if extra > 0 {
let len = buf.len();
buf.resize(len + extra, 0);
buf.copy_within(start + 1..len, start + 1 + extra);
}
buf[start..start + header.len()].copy_from_slice(header);
}
pub(crate) fn read_le<const N: usize>(input: &[u8], pos: usize) -> Result<[u8; N]> {
let end = pos
.checked_add(N)
.ok_or_else(|| Error::custom("offset overflow"))?;
let slice = input
.get(pos..end)
.ok_or_else(|| Error::custom("truncated integer"))?;
let mut out = [0u8; N];
out.copy_from_slice(slice);
Ok(out)
}
pub(crate) fn read_be<const N: usize>(input: &[u8], pos: usize) -> Result<[u8; N]> {
let end = pos
.checked_add(N)
.ok_or_else(|| Error::custom("offset overflow"))?;
let slice = input
.get(pos..end)
.ok_or_else(|| Error::custom("truncated integer"))?;
let mut out = [0u8; N];
out.copy_from_slice(slice);
Ok(out)
}
pub(crate) struct Cursor<'a> {
input: &'a [u8],
pos: usize,
}
impl<'a> Cursor<'a> {
pub(crate) fn new(input: &'a [u8]) -> Self {
Cursor { input, pos: 0 }
}
#[inline]
pub(crate) fn pos(&self) -> usize {
self.pos
}
#[inline]
pub(crate) fn peek(&self) -> Result<u8> {
self.input
.get(self.pos)
.copied()
.ok_or_else(|| Error::custom("unexpected end of input"))
}
#[inline]
pub(crate) fn byte(&mut self) -> Result<u8> {
let b = self.peek()?;
self.pos += 1;
Ok(b)
}
pub(crate) fn bytes(&mut self, n: usize) -> Result<&'a [u8]> {
let end = self
.pos
.checked_add(n)
.ok_or_else(|| Error::custom("offset overflow"))?;
let slice = self
.input
.get(self.pos..end)
.ok_or_else(|| Error::custom("truncated byte string"))?;
self.pos = end;
Ok(slice)
}
pub(crate) fn take(&mut self, n: usize) -> Result<&'a [u8]> {
self.bytes(n)
}
pub(crate) fn le_u32(&mut self) -> Result<u32> {
let b = read_le::<4>(self.input, self.pos)?;
self.pos += 4;
Ok(u32::from_le_bytes(b))
}
pub(crate) fn be_u16(&mut self) -> Result<u16> {
let b = read_be::<2>(self.input, self.pos)?;
self.pos += 2;
Ok(u16::from_be_bytes(b))
}
pub(crate) fn be_u32(&mut self) -> Result<u32> {
let b = read_be::<4>(self.input, self.pos)?;
self.pos += 4;
Ok(u32::from_be_bytes(b))
}
pub(crate) fn be_u64(&mut self) -> Result<u64> {
let b = read_be::<8>(self.input, self.pos)?;
self.pos += 8;
Ok(u64::from_be_bytes(b))
}
pub(crate) fn until_inclusive(&mut self, byte: u8) -> Result<&'a [u8]> {
let tail = &self.input[self.pos..];
let found = tail
.iter()
.position(|b| *b == byte)
.ok_or_else(|| Error::custom("missing terminator byte"))?;
let end = self.pos + found + 1;
let slice = &self.input[self.pos..end];
self.pos = end;
Ok(slice)
}
pub(crate) fn at_end(&self) -> bool {
self.pos >= self.input.len()
}
pub(crate) fn rewind(&mut self, n: usize) {
self.pos = self.pos.saturating_sub(n);
}
pub(crate) fn seek(&mut self, pos: usize) {
self.pos = pos;
}
pub(crate) fn input(&self) -> &'a [u8] {
self.input
}
}