use crate::PrimitivesError;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct VarInt(pub u64);
impl VarInt {
pub fn from_bytes(data: &[u8]) -> Result<(Self, usize), PrimitivesError> {
if data.is_empty() {
return Err(PrimitivesError::UnexpectedEof);
}
match data[0] {
0xff => {
if data.len() < 9 {
return Err(PrimitivesError::UnexpectedEof);
}
let val = u64::from_le_bytes([
data[1], data[2], data[3], data[4],
data[5], data[6], data[7], data[8],
]);
Ok((VarInt(val), 9))
}
0xfe => {
if data.len() < 5 {
return Err(PrimitivesError::UnexpectedEof);
}
let val = u32::from_le_bytes([data[1], data[2], data[3], data[4]]) as u64;
Ok((VarInt(val), 5))
}
0xfd => {
if data.len() < 3 {
return Err(PrimitivesError::UnexpectedEof);
}
let val = u16::from_le_bytes([data[1], data[2]]) as u64;
Ok((VarInt(val), 3))
}
b => {
Ok((VarInt(b as u64), 1))
}
}
}
pub fn length(&self) -> usize {
if self.0 < 253 {
1
} else if self.0 < 65536 {
3
} else if self.0 < 4294967296 {
5
} else {
9
}
}
pub fn to_bytes(&self) -> Vec<u8> {
let mut buf = vec![0u8; self.length()];
self.put_bytes(&mut buf);
buf
}
pub fn put_bytes(&self, dst: &mut [u8]) -> usize {
let v = self.0;
if v < 0xfd {
dst[0] = v as u8;
1
} else if v < 0x10000 {
dst[0] = 0xfd;
dst[1..3].copy_from_slice(&(v as u16).to_le_bytes());
3
} else if v < 0x100000000 {
dst[0] = 0xfe;
dst[1..5].copy_from_slice(&(v as u32).to_le_bytes());
5
} else {
dst[0] = 0xff;
dst[1..9].copy_from_slice(&v.to_le_bytes());
9
}
}
pub fn upper_limit_inc(&self) -> i32 {
match self.0 {
252 | 65535 => 2,
4294967295 => 4,
u64::MAX => -1,
_ => 0,
}
}
pub fn value(&self) -> u64 {
self.0
}
}
impl From<u64> for VarInt {
fn from(v: u64) -> Self {
VarInt(v)
}
}
impl From<usize> for VarInt {
fn from(v: usize) -> Self {
VarInt(v as u64)
}
}
pub struct BsvReader<'a> {
data: &'a [u8],
pos: usize,
}
impl<'a> BsvReader<'a> {
pub fn new(data: &'a [u8]) -> Self {
BsvReader { data, pos: 0 }
}
pub fn read_bytes(&mut self, n: usize) -> Result<&'a [u8], PrimitivesError> {
if self.pos + n > self.data.len() {
return Err(PrimitivesError::UnexpectedEof);
}
let slice = &self.data[self.pos..self.pos + n];
self.pos += n;
Ok(slice)
}
pub fn read_u8(&mut self) -> Result<u8, PrimitivesError> {
let bytes = self.read_bytes(1)?;
Ok(bytes[0])
}
pub fn read_u16_le(&mut self) -> Result<u16, PrimitivesError> {
let bytes = self.read_bytes(2)?;
Ok(u16::from_le_bytes([bytes[0], bytes[1]]))
}
pub fn read_u32_le(&mut self) -> Result<u32, PrimitivesError> {
let bytes = self.read_bytes(4)?;
Ok(u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
}
pub fn read_u64_le(&mut self) -> Result<u64, PrimitivesError> {
let bytes = self.read_bytes(8)?;
Ok(u64::from_le_bytes([
bytes[0], bytes[1], bytes[2], bytes[3],
bytes[4], bytes[5], bytes[6], bytes[7],
]))
}
pub fn read_varint(&mut self) -> Result<VarInt, PrimitivesError> {
let first = self.read_u8()?;
match first {
0xff => {
let val = self.read_u64_le()?;
Ok(VarInt(val))
}
0xfe => {
let val = self.read_u32_le()? as u64;
Ok(VarInt(val))
}
0xfd => {
let val = self.read_u16_le()? as u64;
Ok(VarInt(val))
}
b => Ok(VarInt(b as u64)),
}
}
pub fn remaining(&self) -> usize {
self.data.len() - self.pos
}
}
pub struct BsvWriter {
buf: Vec<u8>,
}
impl BsvWriter {
pub fn new() -> Self {
BsvWriter { buf: Vec::new() }
}
pub fn with_capacity(capacity: usize) -> Self {
BsvWriter { buf: Vec::with_capacity(capacity) }
}
pub fn write_bytes(&mut self, bytes: &[u8]) {
self.buf.extend_from_slice(bytes);
}
pub fn write_u8(&mut self, val: u8) {
self.buf.push(val);
}
pub fn write_u16_le(&mut self, val: u16) {
self.buf.extend_from_slice(&val.to_le_bytes());
}
pub fn write_u32_le(&mut self, val: u32) {
self.buf.extend_from_slice(&val.to_le_bytes());
}
pub fn write_u64_le(&mut self, val: u64) {
self.buf.extend_from_slice(&val.to_le_bytes());
}
pub fn write_varint(&mut self, varint: VarInt) {
let bytes = varint.to_bytes();
self.buf.extend_from_slice(&bytes);
}
pub fn into_bytes(self) -> Vec<u8> {
self.buf
}
pub fn as_bytes(&self) -> &[u8] {
&self.buf
}
pub fn len(&self) -> usize {
self.buf.len()
}
pub fn is_empty(&self) -> bool {
self.buf.is_empty()
}
}
impl Default for BsvWriter {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
fn le_bytes(v: u64) -> Vec<u8> {
v.to_le_bytes().to_vec()
}
#[test]
fn test_decode_varint() {
let mut input = vec![0xff, 0, 0, 0, 0, 0, 0, 0, 0]; let (vi, sz) = VarInt::from_bytes(&input).unwrap();
assert_eq!(vi.0, 0);
assert_eq!(sz, 9);
input = vec![0xfe, 0, 0, 0, 0];
let (vi, sz) = VarInt::from_bytes(&input).unwrap();
assert_eq!(vi.0, 0);
assert_eq!(sz, 5);
input = vec![0xfd, 0, 0];
let (vi, sz) = VarInt::from_bytes(&input).unwrap();
assert_eq!(vi.0, 0);
assert_eq!(sz, 3);
let input = le_bytes(1);
let (vi, sz) = VarInt::from_bytes(&input).unwrap();
assert_eq!(vi.0, 1);
assert_eq!(sz, 1);
}
#[test]
fn test_decode_varint_too_short() {
assert!(VarInt::from_bytes(&[]).is_err());
assert!(VarInt::from_bytes(&[0xff, 0, 0]).is_err());
assert!(VarInt::from_bytes(&[0xfe, 0]).is_err());
assert!(VarInt::from_bytes(&[0xfd]).is_err());
}
#[test]
fn test_varint_upper_limit_inc() {
assert_eq!(VarInt(0).upper_limit_inc(), 0);
assert_eq!(VarInt(10).upper_limit_inc(), 0);
assert_eq!(VarInt(100).upper_limit_inc(), 0);
assert_eq!(VarInt(252).upper_limit_inc(), 2);
assert_eq!(VarInt(65535).upper_limit_inc(), 2);
assert_eq!(VarInt(4294967295).upper_limit_inc(), 4);
assert_eq!(VarInt(u64::MAX).upper_limit_inc(), -1);
}
#[test]
fn test_varint_byte_length() {
assert_eq!(VarInt(0).to_bytes().len(), 1); assert_eq!(VarInt(252).to_bytes().len(), 1); assert_eq!(VarInt(253).to_bytes().len(), 3); assert_eq!(VarInt(65535).to_bytes().len(), 3); assert_eq!(VarInt(65536).to_bytes().len(), 5); assert_eq!(VarInt(4294967295).to_bytes().len(), 5); assert_eq!(VarInt(4294967296).to_bytes().len(), 9); assert_eq!(VarInt(u64::MAX).to_bytes().len(), 9); }
#[test]
fn test_varint_size() {
assert_eq!(VarInt(252).length(), 1);
assert_eq!(VarInt(253).length(), 3);
assert_eq!(VarInt(65535).length(), 3);
assert_eq!(VarInt(65536).length(), 5);
assert_eq!(VarInt(4294967295).length(), 5);
assert_eq!(VarInt(4294967296).length(), 9);
}
#[test]
fn test_varint_put_bytes() {
let cases: Vec<(u64, Vec<u8>)> = vec![
(0, vec![0x00]),
(1, vec![0x01]),
(252, vec![0xfc]),
(253, vec![0xfd, 0xfd, 0x00]),
(65535, vec![0xfd, 0xff, 0xff]),
(65536, vec![0xfe, 0x00, 0x00, 0x01, 0x00]),
(4294967295, vec![0xfe, 0xff, 0xff, 0xff, 0xff]),
(4294967296, vec![0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00]),
(u64::MAX, vec![0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]),
];
for (value, expected) in cases {
let vi = VarInt(value);
let mut buf = vec![0u8; vi.length()];
let n = vi.put_bytes(&mut buf);
assert_eq!(n, expected.len(), "put_bytes length mismatch for {}", value);
assert_eq!(buf, expected, "put_bytes content mismatch for {}", value);
assert_eq!(vi.to_bytes(), buf, "to_bytes != put_bytes for {}", value);
}
}
#[test]
fn test_bsv_reader_writer_roundtrip() {
let mut writer = BsvWriter::new();
writer.write_u8(0x42);
writer.write_u16_le(0x1234);
writer.write_u32_le(0xDEADBEEF);
writer.write_u64_le(0x0102030405060708);
writer.write_varint(VarInt(300));
writer.write_bytes(b"hello");
let data = writer.into_bytes();
let mut reader = BsvReader::new(&data);
assert_eq!(reader.read_u8().unwrap(), 0x42);
assert_eq!(reader.read_u16_le().unwrap(), 0x1234);
assert_eq!(reader.read_u32_le().unwrap(), 0xDEADBEEF);
assert_eq!(reader.read_u64_le().unwrap(), 0x0102030405060708);
assert_eq!(reader.read_varint().unwrap(), VarInt(300));
assert_eq!(reader.read_bytes(5).unwrap(), b"hello");
assert_eq!(reader.remaining(), 0);
}
#[test]
fn test_bsv_reader_eof() {
let reader_data: &[u8] = &[0x01];
let mut reader = BsvReader::new(reader_data);
assert!(reader.read_u8().is_ok());
assert!(reader.read_u8().is_err());
}
#[test]
fn test_bsv_reader_varint_sizes() {
let mut reader = BsvReader::new(&[0x05]);
assert_eq!(reader.read_varint().unwrap(), VarInt(5));
let mut reader = BsvReader::new(&[0xfd, 0x00, 0x01]);
assert_eq!(reader.read_varint().unwrap(), VarInt(256));
let mut reader = BsvReader::new(&[0xfe, 0x00, 0x00, 0x01, 0x00]);
assert_eq!(reader.read_varint().unwrap(), VarInt(65536));
let mut reader = BsvReader::new(&[0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00]);
assert_eq!(reader.read_varint().unwrap(), VarInt(4294967296));
}
}