structpack/
field.rs

1use std::{marker::PhantomData, ops::Range};
2
3use anyhow::{anyhow, Result};
4use bitvec::{field::BitField, prelude::Msb0, view::BitView};
5use funty::{Floating, Integral};
6use serde::{Deserialize, Serialize};
7
8use crate::{FloatingValue, IntegralValue, NumericValue};
9
10pub trait SizedField {
11    type Value<'a>;
12    fn read<'a>(&self, bytes: &'a [u8]) -> Result<Self::Value<'a>>;
13    fn write(&self, bytes: &mut [u8], value: Self::Value<'_>) -> Result<()>;
14    fn last_bit_exclusive(&self) -> usize;
15    fn bit_len(&self) -> usize;
16}
17
18#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
19pub struct IntegralField<T> {
20    range: Range<usize>,
21    #[serde(skip)]
22    _type: PhantomData<fn() -> T>,
23}
24impl<T> IntegralField<T>
25where
26    T: Integral,
27{
28    pub fn new(range: Range<usize>) -> Option<Self> {
29        if range.is_empty() || range.len() > T::BITS as usize {
30            return None;
31        }
32        Some(Self {
33            range,
34            _type: PhantomData,
35        })
36    }
37
38    fn err_out_of_range(&self, bytes_len: usize) -> anyhow::Error {
39        anyhow!(
40            "field is out of range: {:?} bits for {} bytes",
41            self.range,
42            bytes_len
43        )
44    }
45}
46
47impl<T> SizedField for IntegralField<T>
48where
49    T: Integral,
50{
51    type Value<'a> = T;
52
53    fn read<'a>(&self, bytes: &'a [u8]) -> Result<Self::Value<'a>> {
54        let slice = bytes
55            .view_bits::<Msb0>()
56            .get(self.range.clone())
57            .ok_or_else(|| self.err_out_of_range(bytes.len()))?;
58        Ok(slice.load_be())
59    }
60
61    fn write<'a>(&self, bytes: &'a mut [u8], value: Self::Value<'a>) -> Result<()> {
62        let len = bytes.len();
63        let slice = bytes
64            .view_bits_mut::<Msb0>()
65            .get_mut(self.range.clone())
66            .ok_or_else(|| self.err_out_of_range(len))?;
67        slice.store_be(value);
68        Ok(())
69    }
70
71    fn last_bit_exclusive(&self) -> usize {
72        self.range.end
73    }
74
75    fn bit_len(&self) -> usize {
76        self.range.len()
77    }
78}
79
80#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
81#[serde(tag = "type", rename_all = "SCREAMING_SNAKE_CASE")]
82pub enum GenericIntegralField {
83    I8(IntegralField<i8>),
84    I16(IntegralField<i16>),
85    I32(IntegralField<i32>),
86    I64(IntegralField<i64>),
87    U8(IntegralField<u8>),
88    U16(IntegralField<u16>),
89    U32(IntegralField<u32>),
90    U64(IntegralField<u64>),
91}
92
93impl SizedField for GenericIntegralField {
94    type Value<'a> = IntegralValue;
95
96    fn read<'a>(&self, bytes: &'a [u8]) -> Result<Self::Value<'a>> {
97        Ok(match self {
98            Self::I8(f) => f.read(bytes)?.into(),
99            Self::I16(f) => f.read(bytes)?.into(),
100            Self::I32(f) => f.read(bytes)?.into(),
101            Self::I64(f) => f.read(bytes)?.into(),
102            Self::U8(f) => f.read(bytes)?.into(),
103            Self::U16(f) => f.read(bytes)?.into(),
104            Self::U32(f) => f.read(bytes)?.into(),
105            Self::U64(f) => f.read(bytes)?.into(),
106        })
107    }
108
109    fn write(&self, bytes: &mut [u8], value: Self::Value<'_>) -> Result<()> {
110        match self {
111            Self::I8(f) => f.write(bytes, value.try_into()?),
112            Self::I16(f) => f.write(bytes, value.try_into()?),
113            Self::I32(f) => f.write(bytes, value.try_into()?),
114            Self::I64(f) => f.write(bytes, value.try_into()?),
115            Self::U8(f) => f.write(bytes, value.try_into()?),
116            Self::U16(f) => f.write(bytes, value.try_into()?),
117            Self::U32(f) => f.write(bytes, value.try_into()?),
118            Self::U64(f) => f.write(bytes, value.try_into()?),
119        }
120    }
121
122    fn last_bit_exclusive(&self) -> usize {
123        match self {
124            Self::I8(f) => f.last_bit_exclusive(),
125            Self::I16(f) => f.last_bit_exclusive(),
126            Self::I32(f) => f.last_bit_exclusive(),
127            Self::I64(f) => f.last_bit_exclusive(),
128            Self::U8(f) => f.last_bit_exclusive(),
129            Self::U16(f) => f.last_bit_exclusive(),
130            Self::U32(f) => f.last_bit_exclusive(),
131            Self::U64(f) => f.last_bit_exclusive(),
132        }
133    }
134
135    fn bit_len(&self) -> usize {
136        match self {
137            Self::I8(f) => f.bit_len(),
138            Self::I16(f) => f.bit_len(),
139            Self::I32(f) => f.bit_len(),
140            Self::I64(f) => f.bit_len(),
141            Self::U8(f) => f.bit_len(),
142            Self::U16(f) => f.bit_len(),
143            Self::U32(f) => f.bit_len(),
144            Self::U64(f) => f.bit_len(),
145        }
146    }
147}
148
149#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
150pub struct FloatingField<T> {
151    range: Range<usize>,
152    #[serde(skip)]
153    _type: PhantomData<fn() -> T>,
154}
155impl<T> FloatingField<T>
156where
157    T: Floating,
158{
159    pub fn new(range: Range<usize>) -> Option<Self> {
160        if range.is_empty() || range.len() > T::Raw::BITS as usize {
161            return None;
162        }
163        Some(Self {
164            range,
165            _type: PhantomData,
166        })
167    }
168
169    fn err_out_of_range(&self, bytes_len: usize) -> anyhow::Error {
170        anyhow!(
171            "field is out of range: {:?} bits for {} bytes",
172            self.range,
173            bytes_len
174        )
175    }
176}
177
178#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
179#[serde(tag = "type", rename_all = "SCREAMING_SNAKE_CASE")]
180pub enum GenericFloatingField {
181    F32(FloatingField<f32>),
182    F64(FloatingField<f64>),
183}
184
185impl SizedField for GenericFloatingField {
186    type Value<'a> = FloatingValue;
187
188    fn read<'a>(&self, bytes: &'a [u8]) -> Result<Self::Value<'a>> {
189        Ok(match self {
190            Self::F32(f) => f.read(bytes)?.into(),
191            Self::F64(f) => f.read(bytes)?.into(),
192        })
193    }
194
195    fn write(&self, bytes: &mut [u8], value: Self::Value<'_>) -> Result<()> {
196        match self {
197            Self::F32(f) => f.write(bytes, value.try_into()?),
198            Self::F64(f) => f.write(bytes, value.try_into()?),
199        }
200    }
201
202    fn last_bit_exclusive(&self) -> usize {
203        match self {
204            Self::F32(f) => f.last_bit_exclusive(),
205            Self::F64(f) => f.last_bit_exclusive(),
206        }
207    }
208
209    fn bit_len(&self) -> usize {
210        match self {
211            Self::F32(f) => f.bit_len(),
212            Self::F64(f) => f.bit_len(),
213        }
214    }
215}
216
217impl<T> SizedField for FloatingField<T>
218where
219    T: Floating,
220{
221    type Value<'a> = T;
222
223    fn read<'a>(&self, bytes: &'a [u8]) -> Result<Self::Value<'a>> {
224        let slice = bytes
225            .view_bits::<Msb0>()
226            .get(self.range.clone())
227            .ok_or_else(|| self.err_out_of_range(bytes.len()))?;
228        Ok(T::from_bits(slice.load_be()))
229    }
230
231    fn write<'a>(&self, bytes: &'a mut [u8], value: Self::Value<'a>) -> Result<()> {
232        let len = bytes.len();
233        let slice = bytes
234            .view_bits_mut::<Msb0>()
235            .get_mut(self.range.clone())
236            .ok_or_else(|| self.err_out_of_range(len))?;
237        slice.store_be(value.to_bits());
238        Ok(())
239    }
240
241    fn last_bit_exclusive(&self) -> usize {
242        self.range.end
243    }
244
245    fn bit_len(&self) -> usize {
246        self.range.len()
247    }
248}
249
250#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
251#[serde(tag = "kind", rename_all = "SCREAMING_SNAKE_CASE")]
252pub enum NumericField {
253    Integral(GenericIntegralField),
254    Floating(GenericFloatingField),
255}
256
257impl SizedField for NumericField {
258    type Value<'a> = NumericValue;
259
260    fn read<'a>(&self, bytes: &'a [u8]) -> Result<Self::Value<'a>> {
261        Ok(match self {
262            Self::Integral(i) => i.read(bytes)?.into(),
263            Self::Floating(f) => f.read(bytes)?.into(),
264        })
265    }
266
267    fn write(&self, bytes: &mut [u8], value: Self::Value<'_>) -> Result<()> {
268        match self {
269            Self::Integral(i) => i.write(bytes, value.try_into()?),
270            Self::Floating(f) => f.write(bytes, value.try_into()?),
271        }
272    }
273
274    fn last_bit_exclusive(&self) -> usize {
275        match self {
276            Self::Integral(i) => i.last_bit_exclusive(),
277            Self::Floating(f) => f.last_bit_exclusive(),
278        }
279    }
280
281    fn bit_len(&self) -> usize {
282        match self {
283            Self::Integral(i) => i.bit_len(),
284            Self::Floating(f) => f.bit_len(),
285        }
286    }
287}
288
289#[cfg(test)]
290mod tests {
291    use super::*;
292
293    #[test]
294    fn test() {
295        const DEADBEEF: &[u8] = [0xDE, 0xAD, 0xBE, 0xEF].as_slice();
296        let de_u8 = IntegralField::<u8>::new(0..8).unwrap();
297        let adbe_u16 = IntegralField::<u16>::new(8..24).unwrap();
298        assert_eq!(de_u8.read(DEADBEEF).unwrap(), 0xDE);
299        assert_eq!(adbe_u16.read(DEADBEEF).unwrap(), 0xADBE);
300        let n = GenericIntegralField::U8(de_u8);
301        let u: u8 = n.read(DEADBEEF).unwrap().try_into().unwrap();
302        assert_eq!(u, 0xDE);
303        let i: Result<i8> = n.read(DEADBEEF).unwrap().try_into();
304        assert!(i.is_err());
305    }
306
307    #[test]
308    fn test_f64() {
309        let double: [u8; 8] = (789.456f64).to_be_bytes();
310        let slice = &double[..];
311        let f64_field = FloatingField::<f64>::new(0..64).unwrap();
312        assert_eq!(f64_field.read(slice).unwrap(), 789.456);
313    }
314}