rstmt-core 0.0.2

This crate focuses on building a music theory library that can be used to generate music theory data structures and algorithms.
Documentation
/*
    Appellation: pitches <module>
    Contrib: FL03 <jo3mccain@icloud.com>
*/
use super::{PitchClass, PitchTy};

pitch_class! {
    #[default(C)]
    pub enum Natural {
        C = 0,
        D = 2,
        E = 4,
        F = 5,
        G = 7,
        A = 9,
        B = 11,
    }
}

pitch_class! {
    #[default(C)]
    pub enum Sharp {
        C = 1,
        D = 3,
        F = 6,
        G = 8,
        A = 10,
    }
}

pitch_class! {
    #[default(D)]
    pub enum Flat {
        D = 1,
        E = 3,
        G = 6,
        A = 8,
        B = 10,
    }
}

#[derive(
    Clone,
    Copy,
    Eq,
    Hash,
    Ord,
    PartialEq,
    PartialOrd,
    smart_default::SmartDefault,
    strum::AsRefStr,
    strum::EnumCount,
    strum::EnumIs,
    strum::VariantNames,
)]
#[cfg_attr(
    feature = "serde",
    derive(serde::Deserialize, serde::Serialize),
    serde(rename_all = "lowercase")
)]
#[repr(i8)]
#[strum(serialize_all = "lowercase")]
pub enum Pitches {
    Flat(Flat),
    #[default]
    Natural(Natural),
    Sharp(Sharp),
}

impl Pitches {
    pub fn try_from_value(value: PitchTy) -> Result<Self, crate::Error> {
        if let Ok(n) = Natural::try_from_value(value) {
            Ok(n.as_class())
        } else if let Ok(s) = Sharp::try_from_value(value) {
            Ok(s.as_class())
        } else if let Ok(f) = Flat::try_from_value(value) {
            Ok(f.as_class())
        } else {
            Err(crate::Error::music_error("Invalid pitch value."))
        }
    }

    pub fn value(&self) -> PitchTy {
        match self {
            Pitches::Flat(f) => f.pitch(),
            Pitches::Natural(n) => n.pitch(),
            Pitches::Sharp(s) => s.pitch(),
        }
    }
}

impl core::fmt::Debug for Pitches {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        use Pitches::*;
        match self {
            Flat(cls) => write!(f, "{}", cls.as_ref()),
            Natural(cls) => write!(f, "{}", cls.as_ref()),
            Sharp(cls) => write!(f, "{}#", cls.as_ref()),
        }
    }
}

impl core::fmt::Display for Pitches {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        use Pitches::*;
        match self {
            Flat(cls) => write!(f, "{}", cls.as_ref()),
            Natural(cls) => write!(f, "{}", cls.as_ref()),
            Sharp(cls) => write!(f, "{}#", cls.as_ref()),
        }
    }
}

impl PitchClass for Pitches {
    seal!();

    fn pitch(&self) -> PitchTy {
        self.value()
    }
}

impl From<Pitches> for PitchTy {
    fn from(pitch: Pitches) -> PitchTy {
        pitch.value()
    }
}

impl From<PitchTy> for Pitches {
    fn from(value: PitchTy) -> Pitches {
        Self::try_from_value(value).unwrap_or_default()
    }
}