use crate::error::{Error, Result};
pub(crate) struct BitReader<'a> {
bytes: &'a [u8],
bit_pos: usize,
}
impl<'a> BitReader<'a> {
pub(crate) fn new(bytes: &'a [u8]) -> Self {
Self { bytes, bit_pos: 0 }
}
pub(crate) fn remaining_bits(&self) -> usize {
self.bytes.len() * 8 - self.bit_pos
}
pub(crate) fn u(&mut self, n: usize) -> Result<u64> {
debug_assert!(n <= 64);
if self.remaining_bits() < n {
return Err(Error::Parse(format!(
"RTCM body truncated: need {n} more bits, {} remain",
self.remaining_bits()
)));
}
let mut acc: u64 = 0;
for _ in 0..n {
let byte = self.bytes[self.bit_pos / 8];
let bit = (byte >> (7 - (self.bit_pos % 8))) & 1;
acc = (acc << 1) | u64::from(bit);
self.bit_pos += 1;
}
Ok(acc)
}
pub(crate) fn flag(&mut self) -> Result<bool> {
Ok(self.u(1)? != 0)
}
pub(crate) fn i(&mut self, n: usize) -> Result<i64> {
debug_assert!(n < 64);
let raw = self.u(n)?;
let sign_bit = 1u64 << (n - 1);
if raw & sign_bit != 0 {
Ok(raw as i64 - (1i64 << n))
} else {
Ok(raw as i64)
}
}
pub(crate) fn ism(&mut self, n: usize) -> Result<i64> {
debug_assert!((1..64).contains(&n));
let negative = self.flag()?;
let magnitude = self.u(n - 1)? as i64;
Ok(if negative { -magnitude } else { magnitude })
}
}
pub(crate) struct BitWriter {
bytes: Vec<u8>,
nbits: usize,
}
impl BitWriter {
pub(crate) fn new() -> Self {
Self {
bytes: Vec::new(),
nbits: 0,
}
}
fn push_bit(&mut self, bit: u8) {
let byte_index = self.nbits / 8;
if byte_index >= self.bytes.len() {
self.bytes.push(0);
}
if bit != 0 {
self.bytes[byte_index] |= 1 << (7 - (self.nbits % 8));
}
self.nbits += 1;
}
pub(crate) fn push_u(&mut self, value: u64, n: usize) {
debug_assert!(n <= 64);
for k in (0..n).rev() {
self.push_bit(((value >> k) & 1) as u8);
}
}
pub(crate) fn push_flag(&mut self, value: bool) {
self.push_bit(u8::from(value));
}
pub(crate) fn push_i(&mut self, value: i64, n: usize) {
debug_assert!(n < 64);
let mask = (1u64 << n) - 1;
self.push_u((value as u64) & mask, n);
}
pub(crate) fn push_ism(&mut self, value: i64, n: usize) {
debug_assert!((1..64).contains(&n));
self.push_flag(value < 0);
self.push_u(value.unsigned_abs(), n - 1);
}
pub(crate) fn into_bytes(self) -> Vec<u8> {
self.bytes
}
}