sharkyflac 0.2.0

A pure rust FLAC decoder and encoder
Documentation
#![allow(trivial_numeric_casts)]

#[rustfmt::skip]
macro_rules! uint_generate_inner {
    ($name:ident, $d:tt) => {
        #[allow(unused_macros)]
        macro_rules! $name {
            ($d val:expr) => {{
                $crate::num::$name::new($d val).unwrap()
            }};
        }
    };
}

macro_rules! new_unsigned_int_macros {
    ( $( $name:ident ),+) => {
        $(
            uint_generate_inner!($name, $);
        )+
    }
}

macro_rules! new_unsigned_int {
    ( $( $name:ident, $base:ty, $bit_depth: literal );+) => {
        $(
            #[must_use]
            #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
            #[repr(transparent)]
            pub struct $name($base);

            impl $name {
                pub const ZERO: Self = Self(0);
                pub const ONE: Self = Self(1);

                pub const BITS: u8 = $bit_depth;

                #[doc = concat!("The minimum value that may be contained within a [`", stringify!($name), "`]")]
                pub const MIN: Self = Self(0);

                #[doc = concat!("The maximum value that may be contained within a [`", stringify!($name), "`]")]
                pub const MAX: Self = Self(((2 as $base).pow($bit_depth)) - (1 as $base));

                #[doc = concat!("The maximum value that may be contained within a [`", stringify!($name), "`]")]
                pub const MAX2: $base = Self::MAX.inner();

                #[doc = concat!("Get the inner [`", stringify!($base), "`].")]
                #[inline]
                pub const fn inner(self) -> $base {
                    self.0
                }

                #[doc = concat!("Create a new [`", stringify!($name), "`]. If `x` is larger than [`", stringify!($name), "::MAX`], then [`None`] is returned.")]
                #[inline]
                pub const fn new(x: $base) -> Option<Self> {
                    if x <= Self::MAX.0 {
                        Some(Self(x))
                    } else {
                        None
                    }
                }

                #[doc = concat!("Create a new [`", stringify!($name), "`], clamping `x` to [`", stringify!($name), "::MAX`].")]
                #[inline]
                pub const fn new_clamp(x: $base) -> Self {
                    Self(if x > Self::MAX.0 { Self::MAX.0 } else { x })
                }

                #[doc = concat!("Create a new [`", stringify!($name), "`] without checking for valididty.")]
                #[inline]
                pub const fn new_unchecked(x: $base) -> Self {
                    Self(x)
                }

                #[inline]
                pub const fn wrapping_add_base(self, rhs: $base) -> Self {
                    let mask: $base = (1 << Self::BITS) - 1;
                    Self(self.inner().wrapping_add(rhs) & mask)
                }

                #[inline]
                pub const fn wrapping_add(self, rhs: Self) -> Self {
                    Self(self.wrapping_add_base(rhs.inner()).inner())
                }

                /// ```
                /// # use sharkyflac::num::*;
                ///
                /// assert_eq!(U4::new(0).unwrap().checked_add(U4::MAX), Some(U4::MAX));
                /// assert_eq!(U4::MAX.checked_add(U4::MAX), None);
                /// ```
                #[inline]
                pub const fn checked_add(self, rhs: Self) -> Option<Self> {
                    let sum = self.wrapping_add(rhs);
                    if sum.inner() < self.inner() {
                        None
                    } else {
                        Some(sum)
                    }
                }

                #[inline]
                pub const fn wrapping_sub_base(self, rhs: $base) -> Self {
                    let mask: $base = (1 << Self::BITS) - 1;
                    Self(self.inner().wrapping_sub(rhs) & mask)
                }

                #[inline]
                pub const fn wrapping_sub(self, rhs: Self) -> Self {
                    Self(self.wrapping_sub_base(rhs.inner()).inner())
                }

                #[inline]
                pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
                    if self.inner() > rhs.inner() {
                        None
                    } else {
                        Some(self.wrapping_sub(rhs))
                    }
                }
            }

            impl PartialEq<$base> for $name {
                #[inline]
                fn eq(&self, other: &$base) -> bool {
                    self.0.eq(other)
                }
            }

            impl PartialOrd<$base> for $name {
                #[inline]
                fn partial_cmp(&self, other: &$base) -> Option<std::cmp::Ordering> {
                    self.0.partial_cmp(other)
                }
            }

            impl ::std::fmt::Display for $name {
                fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> Result<(), ::std::fmt::Error> {
                    write!(f, "{}", self.0)
                }
            }

            impl ::std::ops::Add for $name {
                type Output = Self;

                fn add(self, rhs: Self) -> Self::Output {
                    match self.checked_add(rhs) {
                        Some(sum) => sum,
                        None => panic!("Attemped to add with overflow"),
                    }
                }
            }

            impl ::std::ops::AddAssign for $name {
                fn add_assign(&mut self, rhs: Self) {
                    match self.checked_add(rhs) {
                        Some(sum) => *self = sum,
                        None => panic!("Attemped to add with overflow"),
                    }
                }
            }

            impl ::std::ops::Add<$base> for $name {
                type Output = Self;

                fn add(self, rhs: $base) -> Self::Output {
                    let rhs = Self::new(rhs).expect(concat!("`rhs` should be <= `", stringify!($name::MAX), "`"));
                    self + rhs
                }
            }

            impl ::std::ops::AddAssign<$base> for $name {
                fn add_assign(&mut self, rhs: $base) {
                    let rhs = Self::new(rhs).expect(concat!("`rhs` should be <= `", stringify!($name::MAX), "`"));
                    *self += rhs
                }
            }

            impl ::std::ops::Sub for $name {
                type Output = Self;

                fn sub(self, rhs: Self) -> Self::Output {
                    match self.checked_sub(rhs) {
                        Some(sum) => sum,
                        None => panic!("Attemped to subtract with overflow"),
                    }
                }
            }

            impl ::std::ops::SubAssign for $name {
                fn sub_assign(&mut self, rhs: Self) {
                    match self.checked_sub(rhs) {
                        Some(sum) => *self = sum,
                        None => panic!("Attemped to subtract with overflow"),
                    }
                }
            }

           ::concat_idents::concat_idents!(struct_name = NonZero, $name {
                #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
                #[repr(transparent)]
                pub struct struct_name($name);

                impl struct_name {
                    #[inline]
                    pub const fn new(num: $name) -> Option<Self> {
                        if matches!(num, <$name>::ZERO) {
                            None
                        } else {
                            Some(Self(num))
                        }
                    }

                    #[inline]
                    pub const fn get(self) -> $name {
                        self.0
                    }
                }
            });

        )+
    };
}

new_unsigned_int!(
    U3, u8, 3
    ; U4, u8, 4
    ; U5, u8, 5
    ; U6, u8, 6
    ; U15, u16, 15
    ; U20, u32, 20
    ; U24, u32, 24
    ; U31, u32, 31
    ; U36, u64, 36
);

#[macro_use]
pub mod macros {
    new_unsigned_int_macros!(U3, U5, U15, U20, U24, U31, U36);
}