use std::{marker::PhantomData, ops::Range};
use anyhow::{anyhow, Result};
use bitvec::{field::BitField, prelude::Msb0, view::BitView};
use funty::{Floating, Integral};
use serde::{Deserialize, Serialize};
use crate::{FloatingValue, IntegralValue, NumericValue};
pub trait SizedField {
type Value<'a>;
fn read<'a>(&self, bytes: &'a [u8]) -> Result<Self::Value<'a>>;
fn write(&self, bytes: &mut [u8], value: Self::Value<'_>) -> Result<()>;
fn last_bit_exclusive(&self) -> usize;
fn bit_len(&self) -> usize;
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct IntegralField<T> {
range: Range<usize>,
#[serde(skip)]
_type: PhantomData<fn() -> T>,
}
impl<T> IntegralField<T>
where
T: Integral,
{
pub fn new(range: Range<usize>) -> Option<Self> {
if range.is_empty() || range.len() > T::BITS as usize {
return None;
}
Some(Self {
range,
_type: PhantomData,
})
}
fn err_out_of_range(&self, bytes_len: usize) -> anyhow::Error {
anyhow!(
"field is out of range: {:?} bits for {} bytes",
self.range,
bytes_len
)
}
}
impl<T> SizedField for IntegralField<T>
where
T: Integral,
{
type Value<'a> = T;
fn read<'a>(&self, bytes: &'a [u8]) -> Result<Self::Value<'a>> {
let slice = bytes
.view_bits::<Msb0>()
.get(self.range.clone())
.ok_or_else(|| self.err_out_of_range(bytes.len()))?;
Ok(slice.load_be())
}
fn write<'a>(&self, bytes: &'a mut [u8], value: Self::Value<'a>) -> Result<()> {
let len = bytes.len();
let slice = bytes
.view_bits_mut::<Msb0>()
.get_mut(self.range.clone())
.ok_or_else(|| self.err_out_of_range(len))?;
slice.store_be(value);
Ok(())
}
fn last_bit_exclusive(&self) -> usize {
self.range.end
}
fn bit_len(&self) -> usize {
self.range.len()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "SCREAMING_SNAKE_CASE")]
pub enum GenericIntegralField {
I8(IntegralField<i8>),
I16(IntegralField<i16>),
I32(IntegralField<i32>),
I64(IntegralField<i64>),
U8(IntegralField<u8>),
U16(IntegralField<u16>),
U32(IntegralField<u32>),
U64(IntegralField<u64>),
}
impl SizedField for GenericIntegralField {
type Value<'a> = IntegralValue;
fn read<'a>(&self, bytes: &'a [u8]) -> Result<Self::Value<'a>> {
Ok(match self {
Self::I8(f) => f.read(bytes)?.into(),
Self::I16(f) => f.read(bytes)?.into(),
Self::I32(f) => f.read(bytes)?.into(),
Self::I64(f) => f.read(bytes)?.into(),
Self::U8(f) => f.read(bytes)?.into(),
Self::U16(f) => f.read(bytes)?.into(),
Self::U32(f) => f.read(bytes)?.into(),
Self::U64(f) => f.read(bytes)?.into(),
})
}
fn write(&self, bytes: &mut [u8], value: Self::Value<'_>) -> Result<()> {
match self {
Self::I8(f) => f.write(bytes, value.try_into()?),
Self::I16(f) => f.write(bytes, value.try_into()?),
Self::I32(f) => f.write(bytes, value.try_into()?),
Self::I64(f) => f.write(bytes, value.try_into()?),
Self::U8(f) => f.write(bytes, value.try_into()?),
Self::U16(f) => f.write(bytes, value.try_into()?),
Self::U32(f) => f.write(bytes, value.try_into()?),
Self::U64(f) => f.write(bytes, value.try_into()?),
}
}
fn last_bit_exclusive(&self) -> usize {
match self {
Self::I8(f) => f.last_bit_exclusive(),
Self::I16(f) => f.last_bit_exclusive(),
Self::I32(f) => f.last_bit_exclusive(),
Self::I64(f) => f.last_bit_exclusive(),
Self::U8(f) => f.last_bit_exclusive(),
Self::U16(f) => f.last_bit_exclusive(),
Self::U32(f) => f.last_bit_exclusive(),
Self::U64(f) => f.last_bit_exclusive(),
}
}
fn bit_len(&self) -> usize {
match self {
Self::I8(f) => f.bit_len(),
Self::I16(f) => f.bit_len(),
Self::I32(f) => f.bit_len(),
Self::I64(f) => f.bit_len(),
Self::U8(f) => f.bit_len(),
Self::U16(f) => f.bit_len(),
Self::U32(f) => f.bit_len(),
Self::U64(f) => f.bit_len(),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct FloatingField<T> {
range: Range<usize>,
#[serde(skip)]
_type: PhantomData<fn() -> T>,
}
impl<T> FloatingField<T>
where
T: Floating,
{
pub fn new(range: Range<usize>) -> Option<Self> {
if range.is_empty() || range.len() > T::Raw::BITS as usize {
return None;
}
Some(Self {
range,
_type: PhantomData,
})
}
fn err_out_of_range(&self, bytes_len: usize) -> anyhow::Error {
anyhow!(
"field is out of range: {:?} bits for {} bytes",
self.range,
bytes_len
)
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "SCREAMING_SNAKE_CASE")]
pub enum GenericFloatingField {
F32(FloatingField<f32>),
F64(FloatingField<f64>),
}
impl SizedField for GenericFloatingField {
type Value<'a> = FloatingValue;
fn read<'a>(&self, bytes: &'a [u8]) -> Result<Self::Value<'a>> {
Ok(match self {
Self::F32(f) => f.read(bytes)?.into(),
Self::F64(f) => f.read(bytes)?.into(),
})
}
fn write(&self, bytes: &mut [u8], value: Self::Value<'_>) -> Result<()> {
match self {
Self::F32(f) => f.write(bytes, value.try_into()?),
Self::F64(f) => f.write(bytes, value.try_into()?),
}
}
fn last_bit_exclusive(&self) -> usize {
match self {
Self::F32(f) => f.last_bit_exclusive(),
Self::F64(f) => f.last_bit_exclusive(),
}
}
fn bit_len(&self) -> usize {
match self {
Self::F32(f) => f.bit_len(),
Self::F64(f) => f.bit_len(),
}
}
}
impl<T> SizedField for FloatingField<T>
where
T: Floating,
{
type Value<'a> = T;
fn read<'a>(&self, bytes: &'a [u8]) -> Result<Self::Value<'a>> {
let slice = bytes
.view_bits::<Msb0>()
.get(self.range.clone())
.ok_or_else(|| self.err_out_of_range(bytes.len()))?;
Ok(T::from_bits(slice.load_be()))
}
fn write<'a>(&self, bytes: &'a mut [u8], value: Self::Value<'a>) -> Result<()> {
let len = bytes.len();
let slice = bytes
.view_bits_mut::<Msb0>()
.get_mut(self.range.clone())
.ok_or_else(|| self.err_out_of_range(len))?;
slice.store_be(value.to_bits());
Ok(())
}
fn last_bit_exclusive(&self) -> usize {
self.range.end
}
fn bit_len(&self) -> usize {
self.range.len()
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "SCREAMING_SNAKE_CASE")]
pub enum NumericField {
Integral(GenericIntegralField),
Floating(GenericFloatingField),
}
impl SizedField for NumericField {
type Value<'a> = NumericValue;
fn read<'a>(&self, bytes: &'a [u8]) -> Result<Self::Value<'a>> {
Ok(match self {
Self::Integral(i) => i.read(bytes)?.into(),
Self::Floating(f) => f.read(bytes)?.into(),
})
}
fn write(&self, bytes: &mut [u8], value: Self::Value<'_>) -> Result<()> {
match self {
Self::Integral(i) => i.write(bytes, value.try_into()?),
Self::Floating(f) => f.write(bytes, value.try_into()?),
}
}
fn last_bit_exclusive(&self) -> usize {
match self {
Self::Integral(i) => i.last_bit_exclusive(),
Self::Floating(f) => f.last_bit_exclusive(),
}
}
fn bit_len(&self) -> usize {
match self {
Self::Integral(i) => i.bit_len(),
Self::Floating(f) => f.bit_len(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test() {
const DEADBEEF: &[u8] = [0xDE, 0xAD, 0xBE, 0xEF].as_slice();
let de_u8 = IntegralField::<u8>::new(0..8).unwrap();
let adbe_u16 = IntegralField::<u16>::new(8..24).unwrap();
assert_eq!(de_u8.read(DEADBEEF).unwrap(), 0xDE);
assert_eq!(adbe_u16.read(DEADBEEF).unwrap(), 0xADBE);
let n = GenericIntegralField::U8(de_u8);
let u: u8 = n.read(DEADBEEF).unwrap().try_into().unwrap();
assert_eq!(u, 0xDE);
let i: Result<i8> = n.read(DEADBEEF).unwrap().try_into();
assert!(i.is_err());
}
#[test]
fn test_f64() {
let double: [u8; 8] = (789.456f64).to_be_bytes();
let slice = &double[..];
let f64_field = FloatingField::<f64>::new(0..64).unwrap();
assert_eq!(f64_field.read(slice).unwrap(), 789.456);
}
}