rstmt_core/intervals/
qualities.rs

1/*
2    Appellation: qualities <module>
3    Contrib: FL03 <jo3mccain@icloud.com>
4*/
5/// Musically speaking, an [interval quality](Quality) is used to identify the different versions of various musical
6/// objects.
7///
8/// With respect to intervals, the quality is used to identify the different versions of the interval.
9///     - [augmented](Augmented)
10///     - [diminished](Diminished)
11///     - [major](Major)
12///     - [minor](Minor)
13///     - [perfect](Perfect)
14pub trait Quality {
15    private!();
16
17    fn phantom() -> PhantomData<Self> {
18        PhantomData::<Self>
19    }
20
21    fn kind() -> IntervalQuality {
22        match Self::name() {
23            "Augmented" => IntervalQuality::augmented(),
24            "Diminished" => IntervalQuality::diminished(),
25            "Major" => IntervalQuality::major(),
26            "Minor" => IntervalQuality::minor(),
27            "Perfect" => IntervalQuality::perfect(),
28            _ => unreachable!(),
29        }
30    }
31
32    fn name() -> &'static str {
33        core::any::type_name::<Self>()
34    }
35
36    fn is_augmented() -> bool {
37        false
38    }
39
40    fn is_diminished() -> bool {
41        false
42    }
43
44    fn is_perfect() -> bool {
45        false
46    }
47
48    fn is_major() -> bool {
49        false
50    }
51
52    fn is_minor() -> bool {
53        false
54    }
55}
56
57macro_rules! quality {
58    (@impl $name:ident::$call:ident) => {
59        #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
60        #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize),)]
61        pub enum $name {}
62
63        impl Quality for $name {
64            seal!();
65
66            fn kind() -> IntervalQuality {
67                IntervalQuality::$call()
68            }
69
70            fn name() -> &'static str {
71                stringify!($call)
72            }
73
74            paste::paste! {
75                fn [<is_ $call>]() -> bool {
76                    true
77                }
78            }
79        }
80
81        unsafe impl Send for $name {}
82
83        unsafe impl Sync for $name {}
84    };
85    ($($name:ident::$call:ident),* $(,)?) => {
86        $(
87            quality!(@impl $name::$call);
88        )*
89    };
90}
91
92quality!(
93    Augmented::augmented,
94    Diminished::diminished,
95    Major::major,
96    Minor::minor,
97    Perfect::perfect
98);
99
100use core::marker::PhantomData;
101
102/// This enum provides a more streamlined means of working with the implemented [Quality] types.
103/// Primarily, it provides simple creation routines for otherwise unitializable types.
104#[derive(
105    Clone,
106    Copy,
107    Debug,
108    Eq,
109    Hash,
110    Ord,
111    PartialEq,
112    PartialOrd,
113    strum::AsRefStr,
114    strum::Display,
115    strum::EnumCount,
116    strum::EnumIs,
117    strum::EnumIter,
118    strum::EnumString,
119    strum::VariantNames,
120)]
121#[cfg_attr(
122    feature = "serde",
123    derive(serde::Deserialize, serde::Serialize),
124    serde(rename_all = "lowercase")
125)]
126#[non_exhaustive]
127#[strum(serialize_all = "lowercase")]
128pub enum IntervalQuality {
129    Augmented(PhantomData<Augmented>),
130    Diminished(PhantomData<Diminished>),
131    Major(PhantomData<Major>),
132    Minor(PhantomData<Minor>),
133    Perfect(PhantomData<Perfect>),
134}
135
136impl IntervalQuality {
137    pub fn new<Q: Quality>() -> Self {
138        Q::kind()
139    }
140    pub fn augmented() -> Self {
141        IntervalQuality::Augmented(PhantomData)
142    }
143
144    pub fn diminished() -> Self {
145        IntervalQuality::Diminished(PhantomData)
146    }
147
148    pub fn major() -> Self {
149        IntervalQuality::Major(PhantomData)
150    }
151
152    pub fn minor() -> Self {
153        IntervalQuality::Minor(PhantomData)
154    }
155
156    pub fn perfect() -> Self {
157        IntervalQuality::Perfect(PhantomData)
158    }
159
160    pub fn from_str(value: &str) -> Option<Self> {
161        match value {
162            "Augmented" | "augmented" => Some(IntervalQuality::augmented()),
163            "Diminished" | "diminished" => Some(IntervalQuality::diminished()),
164            "Major" | "major" => Some(IntervalQuality::major()),
165            "Minor" | "minor" => Some(IntervalQuality::minor()),
166            "Perfect" | "perfect" => Some(IntervalQuality::perfect()),
167            _ => None,
168        }
169    }
170}