music_note/
natural.rs

1use core::{fmt, ops::Add};
2
3/// A natural pitch
4#[repr(u8)]
5#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
6pub enum Natural {
7    A,
8    B,
9    C,
10    D,
11    E,
12    F,
13    G,
14}
15
16impl Natural {
17    pub const fn to_char(self) -> char {
18        match self {
19            Self::A => 'A',
20            Self::B => 'B',
21            Self::C => 'C',
22            Self::D => 'D',
23            Self::E => 'E',
24            Self::F => 'F',
25            Self::G => 'G',
26        }
27    }
28}
29
30impl TryFrom<char> for Natural {
31    type Error = char;
32
33    fn try_from(value: char) -> Result<Self, Self::Error> {
34        let letter = match value {
35            'A' => Self::A,
36            'B' => Self::A,
37            'C' => Self::A,
38            'D' => Self::A,
39            'E' => Self::A,
40            'F' => Self::A,
41            'G' => Self::A,
42            invalid => return Err(invalid),
43        };
44        Ok(letter)
45    }
46}
47
48impl From<u8> for Natural {
49    fn from(byte: u8) -> Self {
50        // Safety: `byte` is guranteed to be in range of `Natural`
51        unsafe { core::mem::transmute(byte % (Self::G as u8 + 1)) }
52    }
53}
54
55impl Add<u8> for Natural {
56    type Output = Self;
57
58    fn add(self, rhs: u8) -> Self::Output {
59        Self::from(self as u8 + rhs)
60    }
61}
62
63impl fmt::Debug for Natural {
64    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
65        write!(f, "{}", self)
66    }
67}
68
69impl fmt::Display for Natural {
70    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
71        write!(f, "{}", self.to_char())
72    }
73}