eryon_nrt/triad/
factors.rs

1/*
2    Appellation: factors <module>
3    Contrib: FL03 <jo3mccain@icloud.com>
4*/
5use strum::IntoEnumIterator;
6
7/// A [chord factor](Components) describes the position of a note within a [triad](crate::Triad).
8/// The `root` factor is the first note of the triad, the `third` factor is the
9/// second note of the triad, and the `fifth` factor is the third note of the triad.
10#[derive(
11    Clone,
12    Copy,
13    Debug,
14    Eq,
15    Hash,
16    Ord,
17    PartialEq,
18    PartialOrd,
19    strum::AsRefStr,
20    strum::Display,
21    strum::EnumCount,
22    strum::EnumDiscriminants,
23    strum::EnumIs,
24    strum::VariantNames,
25)]
26#[cfg_attr(
27    feature = "serde",
28    derive(serde::Deserialize, serde::Serialize),
29    serde(rename_all = "lowercase"),
30    strum_discriminants(
31        derive(serde::Deserialize, serde::Serialize),
32        serde(rename_all = "lowercase")
33    )
34)]
35#[strum_discriminants(
36    name(Factors),
37    derive(
38        Hash,
39        Ord,
40        PartialOrd,
41        strum::AsRefStr,
42        strum::Display,
43        strum::EnumCount,
44        strum::EnumIter,
45        strum::EnumString,
46        strum::VariantNames
47    )
48)]
49#[repr(usize)]
50pub enum Components<T = usize> {
51    #[strum(serialize = "r", serialize = "root")]
52    Root(T) = 0,
53    #[strum(serialize = "t", serialize = "third")]
54    Third(T) = 1,
55    #[strum(serialize = "f", serialize = "fifth")]
56    Fifth(T) = 2,
57}
58
59impl<T> Components<T> {
60    pub fn new(data: T, factor: Factors) -> Self {
61        match factor {
62            Factors::Root => Self::Root(data),
63            Factors::Third => Self::Third(data),
64            Factors::Fifth => Self::Fifth(data),
65        }
66    }
67    /// Returns the [factor](Factors) of the chord.
68    pub fn factor(&self) -> Factors {
69        match self {
70            Self::Root(_) => Factors::Root,
71            Self::Third(_) => Factors::Third,
72            Self::Fifth(_) => Factors::Fifth,
73        }
74    }
75    /// Initialize a new [fifth](Factors::Fifth) factor.
76    pub fn fifth(data: T) -> Self {
77        Self::Fifth(data)
78    }
79    /// Initialize a new [root](Factors::Root) factor.
80    pub fn root(data: T) -> Self {
81        Self::Root(data)
82    }
83    /// Initialize a new [third](Factors::Third) factor.
84    pub fn third(data: T) -> Self {
85        Self::Third(data)
86    }
87}
88
89mod impl_factors {
90    use super::*;
91
92    impl Factors {
93        pub fn root() -> Self {
94            Self::Root
95        }
96
97        pub fn third() -> Self {
98            Self::Third
99        }
100
101        pub fn fifth() -> Self {
102            Self::Fifth
103        }
104
105        pub fn factors() -> [Self; 3] {
106            use Factors::*;
107            [Root, Third, Fifth]
108        }
109
110        pub fn others(&self) -> Vec<Self> {
111            Self::iter().filter(|x| x != self).collect()
112        }
113    }
114
115    impl Default for Factors {
116        fn default() -> Self {
117            Factors::Root
118        }
119    }
120
121    impl From<usize> for Factors {
122        fn from(x: usize) -> Self {
123            use strum::EnumCount;
124            match x % Self::COUNT {
125                0 => Factors::Root,
126                1 => Factors::Third,
127                _ => Factors::Fifth,
128            }
129        }
130    }
131
132    impl From<Factors> for usize {
133        fn from(x: Factors) -> Self {
134            x as usize
135        }
136    }
137}
138
139#[cfg(test)]
140mod tests {
141    use super::*;
142
143    #[test]
144    fn chord_factors() {
145
146        // let triad =
147    }
148
149    #[test]
150    fn chord_factors_iter() {
151        use Factors::*;
152
153        let factors = Factors::factors();
154        assert_eq!(factors.len(), 3);
155        assert_eq!(factors[0], Root);
156        assert_eq!(factors[1], Third);
157        assert_eq!(factors[2], Fifth);
158    }
159}