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 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
//! Types for context representation
//! See [ctx attribute](super::attributes#ctx) for more information.
use core::marker::PhantomData;
use core::str::FromStr;
/// An endian
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum Endian {
/// Little endian
Little,
/// Big endian
Big,
}
/// Error returned when parsing a `Endian` using [`from_str`]
///
/// [`from_str`]: Endian::from_str()
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ParseEndianError {}
impl Endian {
/// [`Endian::default`], but const.
///
/// [`Endian::default`]: Endian::default()
#[inline]
pub const fn new() -> Self {
#[cfg(target_endian = "little")]
let endian = Endian::Little;
#[cfg(target_endian = "big")]
let endian = Endian::Big;
endian
}
/// Is it little endian
#[inline]
pub fn is_le(self) -> bool {
self == Endian::Little
}
/// Is it big endian
#[inline]
pub fn is_be(self) -> bool {
self == Endian::Big
}
}
impl Default for Endian {
/// Return the endianness of the target's CPU.
#[inline]
fn default() -> Self {
Self::new()
}
}
impl FromStr for Endian {
type Err = ParseEndianError;
/// Parse a `Endian` from a string.
/// # Examples
/// ```rust
/// use std::str::FromStr;
///
/// use deku::ctx::Endian;
/// assert_eq!(FromStr::from_str("little"), Ok(Endian::Little));
/// assert_eq!(FromStr::from_str("big"), Ok(Endian::Big));
/// assert!(<Endian as FromStr>::from_str("not an endian").is_err());
/// ```
#[inline]
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"little" => Ok(Endian::Little),
"big" => Ok(Endian::Big),
_ => Err(ParseEndianError {}),
}
}
}
#[allow(clippy::derive_partial_eq_without_eq)]
// derive_partial_eq_without_eq false positive in struct using traits
// For details: https://github.com/rust-lang/rust-clippy/issues/9413
/// A limit placed on a container's elements
#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd)]
pub enum Limit<T, Predicate: FnMut(&T) -> bool> {
/// Read a specific count of elements
Count(usize),
/// Read until a given predicate holds true
Until(Predicate, PhantomData<T>),
/// Read until a given quantity of bytes have been read
ByteSize(ByteSize),
/// Read until a given quantity of bits have been read
BitSize(BitSize),
/// Read until `reader.end()` is true. Used for `read_all` attribute.
End,
}
impl<T> From<usize> for Limit<T, fn(&T) -> bool> {
#[inline]
fn from(n: usize) -> Self {
Limit::Count(n)
}
}
impl<T, Predicate: for<'a> FnMut(&'a T) -> bool> From<Predicate> for Limit<T, Predicate> {
#[inline]
fn from(predicate: Predicate) -> Self {
Limit::Until(predicate, PhantomData)
}
}
impl<T> From<ByteSize> for Limit<T, fn(&T) -> bool> {
#[inline]
fn from(size: ByteSize) -> Self {
Limit::ByteSize(size)
}
}
impl<T> From<BitSize> for Limit<T, fn(&T) -> bool> {
#[inline]
fn from(size: BitSize) -> Self {
Limit::BitSize(size)
}
}
impl<T, Predicate: for<'a> FnMut(&'a T) -> bool> Limit<T, Predicate> {
/// Constructs a new Limit that reads until the given predicate returns true
/// The predicate is given a reference to the latest read value and must return
/// true to stop reading
#[inline]
pub fn new_until(predicate: Predicate) -> Self {
predicate.into()
}
}
impl<T> Limit<T, fn(&T) -> bool> {
/// Read until `reader.end()` is true
#[inline]
pub fn end() -> Self {
Self::End
}
}
impl<T> Limit<T, fn(&T) -> bool> {
/// Constructs a new Limit that reads until the given number of elements are read
#[inline]
pub fn new_count(count: usize) -> Self {
count.into()
}
/// Constructs a new Limit that reads until the given size
#[inline]
pub fn new_bit_size(size: BitSize) -> Self {
size.into()
}
/// Constructs a new Limit that reads until the given size
#[inline]
pub fn new_byte_size(size: ByteSize) -> Self {
size.into()
}
}
/// The size of field in bytes
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
pub struct ByteSize(pub usize);
/// The size of field in bits
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
pub struct BitSize(pub usize);
impl BitSize {
/// Convert the size in bytes to a bit size.
#[inline]
const fn bits_from_reader(byte_size: usize) -> Self {
// TODO: use checked_mul when const_option is enabled
// link: https://github.com/rust-lang/rust/issues/67441
Self(byte_size * 8)
}
/// Returns the bit size of a type.
/// # Examples
/// ```rust
/// # use deku::ctx::BitSize;
///
/// assert_eq!(BitSize::of::<i32>(), BitSize(4 * 8));
/// ```
#[inline]
pub const fn of<T>() -> Self {
Self::bits_from_reader(core::mem::size_of::<T>())
}
/// Returns the bit size of the pointed-to value
#[inline]
pub fn of_val<T: ?Sized>(val: &T) -> Self {
Self::bits_from_reader(core::mem::size_of_val(val))
}
}