use core::fmt; #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] pub enum Pan { Value(PanValue), Surround, Disabled, } impl Default for Pan { fn default() -> Self { Self::Value(PanValue::CENTER) } } #[derive(Debug, Clone, Copy, PartialEq, Eq)] // please pattern types /// range from 0 to 64 pub struct PanValue(u8); impl PanValue { pub const CENTER: Self = Self(32); pub const LEFT: Self = Self(0); pub const RIGHT: Self = Self(64); pub const MAX_VALID: u8 = 64; #[inline] pub const fn new(value: u8) -> Option { if value > Self::MAX_VALID { None } else { Some(Self(value)) } } #[inline] pub const fn get(self) -> u8 { // could have a range assert_unchecked in here self.0 } pub(crate) const fn scale(self) -> f32 { (self.0 as f32) * const { core::f32::consts::FRAC_PI_2 / Self::MAX_VALID as f32 } } } #[cfg(feature = "arbitrary")] impl<'a> arbitrary::Arbitrary<'a> for PanValue { fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { Ok(Self(u.int_in_range(0..=Self::MAX_VALID)?)) } fn size_hint(_depth: usize) -> (usize, Option) { (1, Some(1)) } } #[derive(Clone, Copy, PartialEq, Eq)] // always a valid pan pub struct PackedPan(u8); #[cfg(feature = "arbitrary")] impl<'a> arbitrary::Arbitrary<'a> for PackedPan { fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { Ok(Self::from(Pan::arbitrary(u)?)) } fn size_hint(depth: usize) -> (usize, Option) { Pan::size_hint(depth) } } impl PackedPan { pub(crate) const SURROUND: u8 = 100; pub(crate) const DISABLED: u8 = 128; #[inline] pub const fn get(self) -> Pan { match self.0 { Self::SURROUND => Pan::Surround, Self::DISABLED => Pan::Disabled, // could be unchecked, but this should be done by the compiler 0..=PanValue::MAX_VALID => Pan::Value(PanValue::new(self.0).unwrap()), // could be unchecked _ => unreachable!(), } } pub(crate) const fn new(value: u8) -> Option { if value == Self::SURROUND || value == Self::DISABLED || value <= PanValue::MAX_VALID { Some(Self(value)) } else { None } } pub(crate) const fn get_inner(self) -> u8 { self.0 } } impl From for PackedPan { fn from(value: Pan) -> Self { match value { Pan::Value(v) => Self(v.get()), Pan::Surround => Self(Self::SURROUND), Pan::Disabled => Self(Self::DISABLED), } } } impl Default for PackedPan { fn default() -> Self { Pan::default().into() } } impl fmt::Debug for PackedPan { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Packed") .field("value", &self.get()) .finish() } }