mod iter;
pub(crate) use iter::{RawDataIter, RawDataIterNext};
pub trait RawData:
Sized
+ private::Sealed
+ RawDataIterNext<LittleEndian>
+ RawDataIterNext<BigEndian>
+ From<<Self as RawData>::Storage>
{
type Storage;
const BITS_PER_PIXEL: usize;
fn into_inner(self) -> Self::Storage;
fn from_u32(value: u32) -> Self;
}
impl RawData for () {
type Storage = ();
const BITS_PER_PIXEL: usize = 0;
fn into_inner(self) {}
fn from_u32(_value: u32) {}
}
impl private::Sealed for () {}
macro_rules! impl_raw_data {
($type:ident : $storage_type:ident, $bpp:expr, $mask:expr, $bpp_str:expr, $doc:expr) => {
#[doc = $bpp_str]
#[doc = "per pixel raw data."]
#[doc = ""]
#[doc = $doc]
#[doc = ""]
#[doc = "See the [module-level documentation] for more information."]
#[doc = ""]
#[doc = "[module-level documentation]: index.html"]
#[doc = "[`new`]: #method.new"]
#[doc = "[`into_inner`]: trait.RawData.html#tymethod.into_inner"]
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
pub struct $type($storage_type);
impl $type {
#[doc = $bpp_str]
pub const fn new(value: $storage_type) -> Self {
$type(value & $mask)
}
}
impl RawData for $type {
type Storage = $storage_type;
const BITS_PER_PIXEL: usize = $bpp;
fn into_inner(self) -> Self::Storage {
self.0
}
fn from_u32(value: u32) -> Self {
#[allow(trivial_numeric_casts)]
Self::new(value as $storage_type)
}
}
impl From<$storage_type> for $type {
fn from(value: $storage_type) -> Self {
Self::new(value)
}
}
impl private::Sealed for $type {}
};
($type:ident : $storage_type:ident, $bpp:expr, $mask:expr, $bpp_str:expr) => {
impl_raw_data!(
$type: $storage_type,
$bpp, $mask, $bpp_str,
concat!(
"`", stringify!($type), "` is internally stored in an `", stringify!($storage_type),
"`. It can be constructed from an `", stringify!($storage_type), "` by using the ",
"[`new`] method or by calling `",
stringify!($type), "::from(", stringify!($storage_type),"_value)`. ",
"To convert a `", stringify!($type), "` back into a `", stringify!($storage_type),
"` the [`into_inner`] method can be used."
)
);
};
}
impl_raw_data!(RawU1: u8, 1, 0x01, "1 bit");
impl_raw_data!(RawU2: u8, 2, 0x03, "2 bits");
impl_raw_data!(RawU4: u8, 4, 0x0F, "4 bits");
impl_raw_data!(RawU8: u8, 8, 0xFF, "8 bits");
impl_raw_data!(RawU16: u16, 16, 0xFFFF, "16 bits");
impl_raw_data!(RawU24: u32, 24, 0xFF_FFFF, "24 bits");
impl_raw_data!(RawU32: u32, 32, 0xFFFF_FFFF, "32 bits");
pub trait ByteOrder: private::Sealed {}
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub enum LittleEndian {}
impl ByteOrder for LittleEndian {}
impl private::Sealed for LittleEndian {}
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub enum BigEndian {}
impl ByteOrder for BigEndian {}
impl private::Sealed for BigEndian {}
mod private {
pub trait Sealed {}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn upper_bits_are_masked() {
assert_eq!(RawU1::new(u8::max_value()).0, 0x1);
assert_eq!(RawU2::new(u8::max_value()).0, 0x3);
assert_eq!(RawU4::new(u8::max_value()).0, 0xF);
assert_eq!(RawU24::new(u32::max_value()).0, 0xFFFFFF);
}
}