use core::fmt; #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] pub enum PatternOrder { // please pattern types i need you // somehow enforce that this stays below 200 Number(PatternNumber), #[default] EndOfSong, SkipOrder, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct PatternNumber(u8); impl PatternNumber { pub const MAX_VALID: u8 = 199; #[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 self.0 } } #[cfg(feature = "arbitrary")] impl<'a> arbitrary::Arbitrary<'a> for PatternNumber { 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)] // this is always a valid PatternOrder. Values 200..254 don't appear. i want pattern types pub struct PackedPatternOrder(u8); #[cfg(feature = "arbitrary")] impl<'a> arbitrary::Arbitrary<'a> for PackedPatternOrder { fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { Ok(Self::from(PatternOrder::arbitrary(u)?)) } fn size_hint(depth: usize) -> (usize, Option) { PatternOrder::size_hint(depth) } } impl PackedPatternOrder { pub(crate) const END_OF_SONG: u8 = 255; pub(crate) const SKIP_ORDER: u8 = 254; #[inline] pub const fn get(self) -> PatternOrder { match self.0 { Self::END_OF_SONG => PatternOrder::EndOfSong, Self::SKIP_ORDER => PatternOrder::SkipOrder, 0..=PatternNumber::MAX_VALID => { // the compiler should figure this unwrap out PatternOrder::Number(PatternNumber::new(self.0).unwrap()) } // could be unchecked _ => unreachable!(), } } pub(crate) const fn new(value: u8) -> Option { if value == Self::END_OF_SONG || value == Self::SKIP_ORDER || value <= PatternNumber::MAX_VALID { Some(Self(value)) } else { None } } #[inline] pub(crate) const fn get_inner(self) -> u8 { self.0 } } impl From for PackedPatternOrder { fn from(value: PatternOrder) -> Self { match value { PatternOrder::Number(n) => Self(n.get()), PatternOrder::EndOfSong => Self(Self::END_OF_SONG), PatternOrder::SkipOrder => Self(Self::SKIP_ORDER), } } } impl Default for PackedPatternOrder { fn default() -> Self { PatternOrder::default().into() } } impl fmt::Debug for PackedPatternOrder { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Packed") .field("value", &self.get()) .finish() } }