use crate::errors::CodecError;
use crate::traits::RpcCodec;
pub struct Cursor<'b> {
buf: &'b [u8],
pos: usize,
}
impl<'b> Cursor<'b> {
pub fn new(buf: &'b [u8]) -> Self {
Self { buf, pos: 0 }
}
pub fn inner(&self) -> &'b [u8] {
self.buf
}
pub fn ensure_space(&self, need: usize) -> Result<(), CodecError> {
let min_len = self.pos + need;
if self.buf.len() < min_len {
Err(CodecError::InputTooShort)
} else {
Ok(())
}
}
pub fn remaining_bytes(&self) -> usize {
self.buf.len() - self.pos
}
pub fn is_at_end(&self) -> bool {
self.remaining_bytes() == 0
}
pub fn take_buf(&mut self, need: usize) -> Result<&[u8], CodecError> {
self.ensure_space(need)?;
let start = self.pos;
let end = self.pos + need;
self.pos = end;
Ok(&self.buf[start..end])
}
pub fn take_arr<const N: usize>(&mut self) -> Result<[u8; N], CodecError> {
self.ensure_space(N)?;
let start = self.pos;
let end = self.pos + N;
let mut dbuf = [0; N];
dbuf.copy_from_slice(&self.buf[start..end]);
self.pos = end;
Ok(dbuf)
}
pub fn take_u32(&mut self) -> Result<u32, CodecError> {
let src = self.take_arr::<4>()?;
Ok(u32::from_be_bytes(src))
}
pub fn take_len_tagged_inst<T: RpcCodec>(&mut self) -> Result<T, CodecError> {
let t_len = self.take_u32()?;
let t_buf = self.take_buf(t_len as usize)?;
Ok(T::from_slice(t_buf)?)
}
}
pub fn write_u32(v: u32, buf: &mut Vec<u8>) {
buf.extend_from_slice(&v.to_be_bytes());
}
pub fn write_u32_at(v: u32, pos: usize, buf: &mut Vec<u8>) {
let min_len = pos + 4;
if buf.len() < min_len {
buf.resize(min_len, 0);
}
buf[pos..(pos + 4)].copy_from_slice(&v.to_be_bytes())
}
pub fn write_len_tagged_inst<T: RpcCodec>(t: &T, buf: &mut Vec<u8>) -> Result<(), CodecError> {
let pos = buf.len();
buf.extend_from_slice(&[0; 4]);
t.fill_buf(buf)?;
let t_len = (buf.len() - pos - 4) as u32; write_u32_at(t_len, pos, buf);
Ok(())
}