notation_dsl/fretted/
fretboard.rs

1use fehler::throws;
2use notation_proto::prelude::{
3    Fretboard4, Fretboard6, FrettedEntry4, FrettedEntry6, GuitarTuning,
4    GUITAR_FRET_NUM_ACOUSTIC, Pitch, Octave,
5};
6use notation_proto::proto_entry::ProtoEntry;
7use proc_macro2::TokenStream;
8use quote::{quote, ToTokens};
9use syn::parse::{Error, Parse, ParseStream};
10use syn::{Ident, LitInt, Token};
11
12use crate::context::Context;
13
14pub struct FretboardDsl {
15    pub tuning: Option<Ident>,
16    pub fret_num: Option<usize>,
17    pub capo: Option<u8>,
18}
19
20mod kw {
21    syn::custom_keyword!(tuning);
22    syn::custom_keyword!(fret_num);
23    syn::custom_keyword!(capo);
24}
25
26impl Parse for FretboardDsl {
27    #[throws(Error)]
28    fn parse(input: ParseStream) -> Self {
29        let mut fret_num = None;
30        let mut tuning = None;
31        let mut capo = None;
32        loop {
33            if input.peek(kw::tuning) {
34                input.parse::<kw::tuning>()?;
35                input.parse::<Token![:]>()?;
36                tuning = Some(input.parse::<Ident>()?);
37            } else if input.peek(kw::fret_num) {
38                input.parse::<kw::fret_num>()?;
39                input.parse::<Token![:]>()?;
40                fret_num = Some(input.parse::<LitInt>()?.base10_parse::<usize>()?);
41            } else if input.peek(kw::capo) {
42                input.parse::<kw::capo>()?;
43                input.parse::<Token![:]>()?;
44                capo = Some(input.parse::<LitInt>()?.base10_parse::<u8>()?);
45            } else {
46                break;
47            }
48        }
49        FretboardDsl {
50            tuning,
51            fret_num,
52            capo,
53        }
54    }
55}
56
57impl ToTokens for FretboardDsl {
58    fn to_tokens(&self, tokens: &mut TokenStream) {
59        let FretboardDsl {
60            tuning,
61            fret_num,
62            capo,
63        } = self;
64        let string_num = Context::fretted().string_num;
65        let fret_num = fret_num.unwrap_or(match string_num {
66            6 => GUITAR_FRET_NUM_ACOUSTIC,
67            _ => GUITAR_FRET_NUM_ACOUSTIC,
68        });
69        let capo = capo.unwrap_or(0);
70        let tuning_quote = match tuning {
71            Some(tuning) => {
72                let tuning_quote = tuning.to_string();
73                match string_num {
74                    _ => quote! { GuitarTuning::from_ident(#tuning_quote)},
75                }
76            }
77            None => match string_num {
78                _ => quote! { GuitarTuning::Standard },
79            },
80        };
81        let fretted_entry_quote = Context::fretted().fretted_entry_quote();
82        let fretboard_quote = Context::fretted().fretboard_quote();
83        tokens.extend(quote! {
84            ProtoEntry::from(#fretted_entry_quote::from(
85                #fretboard_quote::new(#fret_num, #tuning_quote.into(), #capo)
86            ))
87        });
88    }
89}
90
91impl FretboardDsl {
92    pub fn to_proto(&self) -> ProtoEntry {
93        let FretboardDsl {
94            tuning,
95            fret_num,
96            capo,
97        } = self;
98        let string_num = Context::fretted().string_num;
99        let fret_num = fret_num.unwrap_or(match string_num {
100            6 => GUITAR_FRET_NUM_ACOUSTIC,
101            _ => GUITAR_FRET_NUM_ACOUSTIC,
102        });
103        let capo = capo.unwrap_or(0);
104        match string_num {
105            4 => {
106                let tuning = [(Pitch::E, Octave::P2).into(); 4]; //todo;
107                ProtoEntry::from(FrettedEntry4::from(Fretboard4::new(fret_num, tuning, capo)))
108            }
109            _ => {
110                let tuning = match tuning {
111                    Some(ident) => GuitarTuning::from_ident(ident.to_string().as_str()),
112                    None => GuitarTuning::Standard,
113                };
114                ProtoEntry::from(FrettedEntry6::from(Fretboard6::new(
115                    fret_num,
116                    tuning.into(),
117                    capo,
118                )))
119            }
120        }
121    }
122}