rstmt_nrt/types/
factors.rs

1/*
2    Appellation: factors <module>
3    Contrib: FL03 <jo3mccain@icloud.com>
4*/
5use strum::IntoEnumIterator;
6
7/// The [`ChordFactor`] implementation enumerates the various notes within a triad, essentially
8/// providing an _index_ for each of the chord's components.
9#[derive(
10    Clone,
11    Copy,
12    Debug,
13    Eq,
14    Hash,
15    Ord,
16    PartialEq,
17    PartialOrd,
18    strum::AsRefStr,
19    strum::Display,
20    strum::EnumCount,
21    strum::EnumDiscriminants,
22    strum::EnumIs,
23    strum::VariantNames,
24)]
25#[cfg_attr(
26    feature = "serde",
27    derive(serde::Deserialize, serde::Serialize),
28    serde(rename_all = "lowercase"),
29    strum_discriminants(
30        derive(serde::Deserialize, serde::Serialize),
31        serde(rename_all = "lowercase")
32    )
33)]
34#[strum_discriminants(
35    name(Factors),
36    derive(
37        Hash,
38        Ord,
39        PartialOrd,
40        strum::AsRefStr,
41        strum::Display,
42        strum::EnumCount,
43        strum::EnumIter,
44        strum::EnumString,
45        strum::VariantArray,
46        strum::VariantNames
47    ),
48    strum(serialize_all = "lowercase")
49)]
50#[repr(usize)]
51#[strum(serialize_all = "lowercase")]
52pub enum ChordFactor<T = usize> {
53    #[strum(serialize = "r", serialize = "root")]
54    Root(T) = 0,
55    #[strum(serialize = "t", serialize = "third")]
56    Third(T) = 1,
57    #[strum(serialize = "f", serialize = "fifth")]
58    Fifth(T) = 2,
59}
60
61impl Factors {
62    /// a functional constructor for the [`Root`](Self::Root) variant
63    pub const fn root() -> Self {
64        Self::Root
65    }
66    /// a functional constructor for the [`Third`](Self::Third) variant
67    pub const fn third() -> Self {
68        Self::Third
69    }
70    /// a functional constructor for the [`Fifth`](Self::Fifth) variant
71    pub const fn fifth() -> Self {
72        Self::Fifth
73    }
74    /// returns an array of the possible [`Factors`] variants
75    pub fn factors_as_slice() -> [Self; 3] {
76        use Factors::*;
77        [Root, Third, Fifth]
78    }
79    #[cfg(feature = "alloc")]
80    /// returns a collection of all the other variants except the one that is called on
81    pub fn others(&self) -> alloc::vec::Vec<Self> {
82        Self::iter().filter(|x| x != self).collect()
83    }
84}
85
86impl<T> ChordFactor<T> {
87    pub const fn new(data: T, factor: Factors) -> Self {
88        match factor {
89            Factors::Root => Self::Root(data),
90            Factors::Third => Self::Third(data),
91            Factors::Fifth => Self::Fifth(data),
92        }
93    }
94    /// Returns the [factor](Factors) of the chord.
95    pub const fn factor(&self) -> Factors {
96        match self {
97            Self::Root(_) => Factors::Root,
98            Self::Third(_) => Factors::Third,
99            Self::Fifth(_) => Factors::Fifth,
100        }
101    }
102    /// Initialize a new [fifth](Factors::Fifth) factor.
103    pub const fn fifth(data: T) -> Self {
104        Self::Fifth(data)
105    }
106    /// Initialize a new [root](Factors::Root) factor.
107    pub const fn root(data: T) -> Self {
108        Self::Root(data)
109    }
110    /// Initialize a new [third](Factors::Third) factor.
111    pub const fn third(data: T) -> Self {
112        Self::Third(data)
113    }
114    #[inline]
115    /// consumes the current instance to reveal the inner value.
116    pub fn value(self) -> T {
117        match self {
118            Self::Root(inner) => inner,
119            Self::Third(inner) => inner,
120            Self::Fifth(inner) => inner,
121        }
122    }
123    /// returns a reference to the value of the current factor
124    pub const fn get(&self) -> &T {
125        match self {
126            Self::Root(inner) => inner,
127            Self::Third(inner) => inner,
128            Self::Fifth(inner) => inner,
129        }
130    }
131    /// returns a mutable reference to the value of the current factor
132    pub const fn get_mut(&mut self) -> &mut T {
133        match self {
134            Self::Root(inner) => inner,
135            Self::Third(inner) => inner,
136            Self::Fifth(inner) => inner,
137        }
138    }
139}
140
141impl Default for Factors {
142    fn default() -> Self {
143        Factors::Root
144    }
145}
146
147macro_rules! impl_from_factor {
148    (@impl $T:ty) => {
149        impl From<$T> for Factors {
150            fn from(x: $T) -> Self {
151                use strum::EnumCount;
152                match x % Self::COUNT as $T {
153                    0 => Factors::Root,
154                    1 => Factors::Third,
155                    2 => Factors::Fifth,
156                    _ => unreachable!("Modular arithmetic error"), 
157                }
158            }
159        }
160
161        impl From<Factors> for $T {
162            fn from(x: Factors) -> Self {
163                x as $T
164            }
165        }
166    };
167    ($($T:ty),* $(,)?) => {
168        $(impl_from_factor! { @impl $T })*
169    }
170}
171
172impl_from_factor! { u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize }
173
174
175#[cfg(test)]
176mod tests {
177    use super::*;
178
179    #[test]
180    fn chord_factors() {
181
182        // let triad =
183    }
184
185    #[test]
186    fn chord_factors_iter() {
187        use Factors::*;
188
189        let factors = Factors::factors_as_slice();
190        assert_eq! { factors, [Root, Third, Fifth] }
191    }
192}