rstmt-nrt 0.1.0

this crate focuses on providing support for the neo-riemannian theory of music
Documentation
/*
    Appellation: factors <module>
    Contrib: FL03 <jo3mccain@icloud.com>
*/
use strum::IntoEnumIterator;

/// The [`ChordFactor`] implementation enumerates the various notes within a triad, essentially
/// providing an _index_ for each of the chord's components.
#[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 {
    /// a functional constructor for the [`Root`](Self::Root) variant
    pub const fn root() -> Self {
        Self::Root
    }
    /// a functional constructor for the [`Third`](Self::Third) variant
    pub const fn third() -> Self {
        Self::Third
    }
    /// a functional constructor for the [`Fifth`](Self::Fifth) variant
    pub const fn fifth() -> Self {
        Self::Fifth
    }
    /// returns an array of the possible [`Factors`] variants
    pub fn factors_as_slice() -> [Self; 3] {
        use Factors::*;
        [Root, Third, Fifth]
    }
    #[cfg(feature = "alloc")]
    /// returns a collection of all the other variants except the one that is called on
    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),
        }
    }
    /// Returns the [factor](Factors) of the chord.
    pub const fn factor(&self) -> Factors {
        match self {
            Self::Root(_) => Factors::Root,
            Self::Third(_) => Factors::Third,
            Self::Fifth(_) => Factors::Fifth,
        }
    }
    /// Initialize a new [fifth](Factors::Fifth) factor.
    pub const fn fifth(data: T) -> Self {
        Self::Fifth(data)
    }
    /// Initialize a new [root](Factors::Root) factor.
    pub const fn root(data: T) -> Self {
        Self::Root(data)
    }
    /// Initialize a new [third](Factors::Third) factor.
    pub const fn third(data: T) -> Self {
        Self::Third(data)
    }
    #[inline]
    /// consumes the current instance to reveal the inner value.
    pub fn value(self) -> T {
        match self {
            Self::Root(inner) => inner,
            Self::Third(inner) => inner,
            Self::Fifth(inner) => inner,
        }
    }
    /// returns a reference to the value of the current factor
    pub const fn get(&self) -> &T {
        match self {
            Self::Root(inner) => inner,
            Self::Third(inner) => inner,
            Self::Fifth(inner) => inner,
        }
    }
    /// returns a mutable reference to the value of the current factor
    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() {

        // let triad =
    }

    #[test]
    fn chord_factors_iter() {
        use Factors::*;

        let factors = Factors::factors_as_slice();
        assert_eq! { factors, [Root, Third, Fifth] }
    }
}