1use crate::key::{Key, Scale};
2use crate::note::Note;
3use crate::Accidental;
4use std::num::NonZeroU8;
5
6#[derive(Copy, Clone, Debug, PartialEq, Eq)]
7#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
8pub struct ScaleDegree {
9 pub degree: NonZeroU8,
10 pub quality: Accidental,
11}
12
13impl ScaleDegree {
14 pub const fn new(degree: u8, quality: Accidental) -> Self {
15 Self {
16 degree: NonZeroU8::new(degree).expect("0 is not a valid scale degree"),
17 quality,
18 }
19 }
20
21 pub fn from_note(note: &Note, key: &Key) -> Option<Self> {
22 let scale = Scale::from(key);
23 scale
24 .notes
25 .iter()
26 .enumerate()
27 .find(|(_, &n)| n.id().simple() == note.id().simple())
28 .map(|(i, _)| Self::new(i as u8 + 1, Accidental::None))
29 }
30}
31
32impl Default for ScaleDegree {
33 fn default() -> Self {
34 Self {
35 degree: NonZeroU8::new(1).expect("1 is not 0 ..."),
36 quality: Accidental::Natural,
37 }
38 }
39}