resonata 0.3.0

A music theory library for Rust.
Documentation
use std::{fmt::{self, Display, Formatter, Debug}, str::FromStr};
use regex::Regex;
use super::super::*;

impl From<IntervalQuality> for i8 {
    fn from(iq: IntervalQuality) -> Self {
        match iq {
            Diminished(n) => -(n as i8) - 1,
            Augmented(n) => n as i8,
            Minor => -1,
            Major => 0,
            Perfect => 0,
        }
    }
}

impl PartialEq for IntervalQuality {
    fn eq(&self, other: &Self) -> bool {
        i8::from(*self) == i8::from(*other)
    }
}

impl Eq for IntervalQuality {}

impl PartialOrd for IntervalQuality {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        let self_i8 = i8::from(*self);
        let other_i8 = i8::from(*other);
        self_i8.partial_cmp(&other_i8)
    }
}

impl Ord for IntervalQuality {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        let self_i8 = i8::from(*self);
        let other_i8 = i8::from(*other);
        self_i8.cmp(&other_i8)
    }
}

impl FromStr for IntervalQuality {
    type Err = ResonataError;
    
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let re = Regex::new(r"^(?P<quality>[#x𝄪b♯♯♭♭♮+-mMpPaAdD\+-]*)").unwrap();
        if let Some(cap) = re.captures(s) {
            let quality_expr = cap.name("quality").map_or("", |x| x.as_str());
            let mut quality = IntervalQuality::Major;
            for c in quality_expr.chars() {
                match c {
                    'm' => quality = IntervalQuality::Minor,
                    'M' => quality = IntervalQuality::Major,
                    'P' => quality = IntervalQuality::Perfect,
                    'A' => quality = IntervalQuality::Augmented(1),
                    'd' => quality = IntervalQuality::Diminished(1),
                    _ => nope!(InvalidIntervalQuality)
                }
            }
            Ok(quality)
        } else {
            err!(InvalidIntervalQuality)
        }
    }
}

impl Display for IntervalQuality {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        let token = match self {
            Diminished(n) => std::iter::repeat('D').take(*n as usize).collect(),
            Augmented(n) => std::iter::repeat('A').take(*n as usize).collect(),
            Minor => "m".to_string(),
            Major => "M".to_string(),
            Perfect => "P".to_string(),
        };

        write!(f, "{}", token)
    }
}

impl Debug for IntervalQuality {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.to_string())
    }
}