1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
#![feature(more_qualified_paths)]
#![no_std]
#[cfg(feature = "non_fixed")]
extern crate alloc;
use core::fmt::Debug;
#[cfg(feature = "non_fixed")]
use alloc::borrow::Cow;
#[derive(Debug)]
/// A generic error encountered while parsing.
pub enum ParserError {
/// The parser expected more data than it got.
TooLittleData(usize),
/// Just like TooLittleData, but more specific.
HeaderIncomplete(usize),
/// The expected magic was invalid.
InvalidMagic,
/// A value wasn't understood by the parser.
ValueNotUnderstood,
}
#[cfg(feature = "non_fixed")]
/// A trait for reading a non fixed amount of data.
pub trait Read
where
Self: Sized,
{
fn from_bytes(data: &mut impl ExactSizeIterator<Item = u8>) -> Result<Self, ParserError>;
}
#[cfg(feature = "non_fixed")]
/// A trait for reading a non fixed amount of data, with context.
pub trait ReadCtx<Ctx>
where
Self: Sized,
{
fn from_bytes(
data: &mut impl ExactSizeIterator<Item = u8>,
ctx: Ctx,
) -> Result<Self, ParserError>;
}
#[cfg(feature = "non_fixed")]
/// A trait for writing data of variable length.
pub trait Write<'a> {
fn to_bytes(&self) -> Cow<'a, [u8]>;
}
/// A trait for reading data of fixed length.
pub trait ReadFixed<const N: usize>
where
Self: Sized,
{
fn from_bytes(data: &[u8; N]) -> Result<Self, ParserError>;
}
/// A trait for reading data of fixed length, with context.
pub trait ReadFixedCtx<const N: usize, Ctx>
where
Self: Sized,
{
fn from_bytes(data: &[u8; N], ctx: Ctx) -> Result<Self, ParserError>;
}
/// A trait for writing data of fixed length.
pub trait WriteFixed<const N: usize>
where
Self: Sized,
{
fn to_bytes(&self) -> [u8; N];
}
#[macro_export]
/// This macro allows turning enums into numbers and vice versa.
/// ```
/// #![feature(more_qualified_paths)]
///
/// #[derive(Debug, PartialEq)]
/// enum ABC {
/// A,
/// B,
/// C,
/// Unknown(u8),
/// }
/// bin_utils::enum_to_int! {
/// u8,
/// ABC,
///
/// 0x01,
/// ABC::A,
/// 0x02,
/// ABC::B,
/// 0x03,
/// ABC::C
/// }
///
/// let a: ABC = 0x01.into();
/// assert_eq!(a, ABC::A);
/// let a: u8 = a.into();
/// assert_eq!(a, 0x01);
/// let unknown: ABC = 0xff.into();
/// assert_eq!(unknown, ABC::Unknown(0xff));
/// ```
macro_rules! enum_to_int {
($a:ty, $b:ty, $($x:expr, $y:path), +) => {
impl From<$a> for $b {
fn from(value: $a) -> Self {
match value {
$($x => $y,)+
_ => Self::Unknown(value),
}
}
}
impl From<$b> for $a {
fn from(value: $b) -> Self {
match value {
$($y => $x,)+
<$b>::Unknown(value) => value
}
}
}
}
}