use std::{fmt::{self, Display, Formatter, Debug}, str::FromStr, ops::{Add, Sub, AddAssign, SubAssign}};
use super::super::*;
impl From<u8> for NoteName {
fn from(value: u8) -> Self {
match value % 7 {
0 => C,
1 => D,
2 => E,
3 => F,
4 => G,
5 => A,
6 => B,
_ => unreachable!(),
}
}
}
impl From<NoteName> for u8 {
fn from(name: NoteName) -> Self {
match name {
C => 0,
D => 2,
E => 4,
F => 5,
G => 7,
A => 9,
B => 11,
}
}
}
impl Add<u8> for NoteName {
type Output = Self;
fn add(self, n: u8) -> Self::Output {
Self::from(u8::from(self) + n % 6)
}
}
impl AddAssign<u8> for NoteName {
fn add_assign(&mut self, n: u8) {
*self = Self::from(u8::from(*self) + n % 6)
}
}
impl Sub<u8> for NoteName {
type Output = Self;
fn sub(self, n: u8) -> Self::Output {
Self::from((u8::from(self) as i8 - n as i8).abs() as u8 % 6)
}
}
impl SubAssign<u8> for NoteName {
fn sub_assign(&mut self, n: u8) {
*self = Self::from((u8::from(*self) as i8 - n as i8).abs() as u8 % 6)
}
}
impl FromStr for NoteName {
type Err = ResonataError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_ascii_lowercase().as_str() {
"c" => Ok(C),
"d" => Ok(D),
"e" => Ok(E),
"f" => Ok(F),
"g" => Ok(G),
"a" => Ok(A),
"b" => Ok(B),
_ => nope!(InvalidNoteName)
}
}
}
impl Display for NoteName {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let token = match self {
C => "C",
D => "D",
E => "E",
F => "F",
G => "G",
A => "A",
B => "B",
};
write!(f, "{}", token)
}
}
impl Debug for NoteName {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.to_string())
}
}