chordparser 4.0.4

A parser library to generate Jazz/Pop/Rock chords from string inputs
Documentation
use crate::chord::{interval::Interval, note::Note};
use std::fmt::{self};

#[derive(Debug, PartialEq, Clone)]
#[repr(u8)]
pub enum Exp {
    Power,
    Bass,
    Maj,
    Maj7,
    Minor,
    HalfDim,
    Dim,
    Dim7,
    Alt,
    Aug,
    Sus(SusExp),
    Extension(ExtensionExp),
    Add(AddExp),
    Omit(OmitExp),
    SlashBass(SlashBassExp),
}

impl Exp {
    pub fn validate(&self) -> (bool, usize) {
        match self {
            Exp::Omit(exp) => exp.isvalid(),
            Exp::Add(exp) => exp.isvalid(),
            _ => (true, 0),
        }
    }

    pub fn priority(&self) -> u32 {
        match self {
            Exp::Power => 0,
            Exp::Alt => 1,
            Exp::Bass => 2,
            Exp::Minor => 3,
            Exp::Dim7 => 4,
            Exp::Dim => 5,
            Exp::HalfDim => 6,
            Exp::Sus(_) => 7,
            Exp::Maj => 8,
            Exp::Maj7 => 9,
            Exp::Extension(_) => 10,
            Exp::Add(_) => 11,
            Exp::Aug => 12,
            Exp::Omit(_) => 13,
            Exp::SlashBass(_) => 14,
        }
    }
    pub fn from_priority(p: u32) -> &'static str {
        match p {
            0 => "5",
            1 => "Alt",
            2 => "Bass",
            3 => "Minor",
            4 => "Dim7",
            5 => "Dim",
            6 => "halfDim",
            7 => "Sus",
            8 => "Maj",
            9 => "Maj",
            10 => "Extension",
            11 => "Add",
            12 => "Aug",
            13 => "Omit",
            14 => "SlashBass",
            _ => "",
        }
    }
}
impl fmt::Display for Exp {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let s = match self {
            Exp::Extension(_) => "Extension",
            Exp::Add(_) => "Add",
            Exp::Sus(_) => "Sus",
            Exp::Omit(_) => "Omit",
            Exp::SlashBass(_) => "SlashBass",
            Exp::Bass => "Bass",
            Exp::Alt => "Alt",
            Exp::Minor => "Minor",
            Exp::Aug => "Aug",
            Exp::HalfDim => "HalfDim",
            Exp::Dim => "Dim",
            Exp::Dim7 => "Dim7",
            Exp::Maj => "Maj",
            Exp::Maj7 => "Maj",
            Exp::Power => "Power",
        };
        write!(f, "{}", s)
    }
}

impl Eq for Exp {}

impl PartialOrd for Exp {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Exp {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        match self.priority().cmp(&other.priority()) {
            std::cmp::Ordering::Equal => match (self, other) {
                (Exp::Extension(expa), Exp::Extension(expb)) => {
                    expa.interval.st().cmp(&expb.interval.st())
                }
                _ => std::cmp::Ordering::Equal,
            },
            other => other,
        }
    }
}

#[derive(Debug, PartialEq, Eq, Clone)]
pub struct ExtensionExp {
    pub interval: Interval,
    pub pos: usize,
}
impl ExtensionExp {
    pub fn new(interval: Interval, pos: usize) -> Self {
        Self { interval, pos }
    }
}

#[derive(Debug, PartialEq, Eq, Clone)]
pub struct AddExp {
    pub interval: Interval,
    pub target_pos: usize,
}

impl AddExp {
    pub fn new(interval: Interval, target_pos: usize) -> Self {
        Self {
            interval,
            target_pos,
        }
    }
    pub fn isvalid(&self) -> (bool, usize) {
        (
            matches!(
                self.interval,
                Interval::MajorSecond
                    | Interval::MajorThird
                    | Interval::PerfectFourth
                    | Interval::MinorSixth
                    | Interval::MajorSixth
                    | Interval::MajorSeventh
                    | Interval::FlatNinth
                    | Interval::Ninth
                    | Interval::SharpNinth
                    | Interval::Eleventh
                    | Interval::SharpEleventh
                    | Interval::FlatThirteenth
                    | Interval::Thirteenth
            ),
            self.target_pos,
        )
    }
}

#[derive(Debug, PartialEq, Eq, Clone)]
pub struct SusExp {
    pub interval: Interval,
}

impl SusExp {
    pub fn new(interval: Interval) -> Self {
        Self { interval }
    }
}

#[derive(Debug, PartialEq, Eq, Clone)]
pub struct OmitExp {
    pub interval: Interval,
    pub target_pos: usize,
}

impl OmitExp {
    pub fn new(interval: Interval, target_pos: usize) -> Self {
        Self {
            interval,
            target_pos,
        }
    }
    pub fn isvalid(&self) -> (bool, usize) {
        (
            matches!(self.interval, Interval::MajorThird | Interval::PerfectFifth),
            self.target_pos,
        )
    }
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct SlashBassExp {
    pub note: Note,
}

impl SlashBassExp {
    pub fn new(note: Note) -> Self {
        Self { note }
    }
}