use strum::IntoEnumIterator;
#[derive(
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
strum::AsRefStr,
strum::Display,
strum::EnumCount,
strum::EnumDiscriminants,
strum::EnumIs,
strum::VariantNames,
)]
#[cfg_attr(
feature = "serde",
derive(serde::Deserialize, serde::Serialize),
serde(rename_all = "lowercase"),
strum_discriminants(
derive(serde::Deserialize, serde::Serialize),
serde(rename_all = "lowercase")
)
)]
#[strum_discriminants(
name(Factors),
derive(
Hash,
Ord,
PartialOrd,
strum::AsRefStr,
strum::Display,
strum::EnumCount,
strum::EnumIter,
strum::EnumString,
strum::VariantArray,
strum::VariantNames
),
strum(serialize_all = "lowercase")
)]
#[repr(usize)]
#[strum(serialize_all = "lowercase")]
pub enum ChordFactor<T = usize> {
#[strum(serialize = "r", serialize = "root")]
Root(T) = 0,
#[strum(serialize = "t", serialize = "third")]
Third(T) = 1,
#[strum(serialize = "f", serialize = "fifth")]
Fifth(T) = 2,
}
impl Factors {
pub const fn root() -> Self {
Self::Root
}
pub const fn third() -> Self {
Self::Third
}
pub const fn fifth() -> Self {
Self::Fifth
}
pub fn factors_as_slice() -> [Self; 3] {
use Factors::*;
[Root, Third, Fifth]
}
#[cfg(feature = "alloc")]
pub fn others(&self) -> alloc::vec::Vec<Self> {
Self::iter().filter(|x| x != self).collect()
}
}
impl<T> ChordFactor<T> {
pub const fn new(data: T, factor: Factors) -> Self {
match factor {
Factors::Root => Self::Root(data),
Factors::Third => Self::Third(data),
Factors::Fifth => Self::Fifth(data),
}
}
pub const fn factor(&self) -> Factors {
match self {
Self::Root(_) => Factors::Root,
Self::Third(_) => Factors::Third,
Self::Fifth(_) => Factors::Fifth,
}
}
pub const fn fifth(data: T) -> Self {
Self::Fifth(data)
}
pub const fn root(data: T) -> Self {
Self::Root(data)
}
pub const fn third(data: T) -> Self {
Self::Third(data)
}
#[inline]
pub fn value(self) -> T {
match self {
Self::Root(inner) => inner,
Self::Third(inner) => inner,
Self::Fifth(inner) => inner,
}
}
pub const fn get(&self) -> &T {
match self {
Self::Root(inner) => inner,
Self::Third(inner) => inner,
Self::Fifth(inner) => inner,
}
}
pub const fn get_mut(&mut self) -> &mut T {
match self {
Self::Root(inner) => inner,
Self::Third(inner) => inner,
Self::Fifth(inner) => inner,
}
}
}
impl Default for Factors {
fn default() -> Self {
Factors::Root
}
}
macro_rules! impl_from_factor {
(@impl $T:ty) => {
impl From<$T> for Factors {
fn from(x: $T) -> Self {
use strum::EnumCount;
match x % Self::COUNT as $T {
0 => Factors::Root,
1 => Factors::Third,
2 => Factors::Fifth,
_ => unreachable!("Modular arithmetic error"),
}
}
}
impl From<Factors> for $T {
fn from(x: Factors) -> Self {
x as $T
}
}
};
($($T:ty),* $(,)?) => {
$(impl_from_factor! { @impl $T })*
}
}
impl_from_factor! { u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn chord_factors() {
}
#[test]
fn chord_factors_iter() {
use Factors::*;
let factors = Factors::factors_as_slice();
assert_eq! { factors, [Root, Third, Fifth] }
}
}