1
2use macroex::{*, proc_macro2::*};
3#[derive(Debug, Clone, Copy, PartialEq)]
19pub struct Angle(pub f32);
20
21pub const PI: f32 = std::f32::consts::PI;
22ident_validator!(LitPi "pi");
23impl FromMacro for Angle {
24
25 fn from_one(tt: proc_macro2::TokenTree) -> Result<Self, Error> {
26 match Either3::from_one(tt)? {
27 Either3::A(Number(f)) => Ok(Self(f)),
28 Either3::B(LitPi) => Ok(Self(PI)),
29 Either3::C(Bracketed(tokens)) => Self::from_many(tokens)
30 }
31 }
32
33 fn from_many(tokens: proc_macro2::TokenStream) -> Result<Self, Error> {
34 let mut iter = tokens.into_iter();
35 match iter.extract()? {
36 Either3::A(LitPi) => {
37 if let Ok(PunctOf::<'/'>) = iter.extract(){
38 let Number::<f32>(numer) = iter.extract()?;
39 let EndOfStream = iter.extract()?;
40 Ok(Self(PI / numer))
41 } else {
42 let EndOfStream = iter.extract()?;
43 Ok(Self(PI))
44 }
45 },
46 Either3::B(Number(value)) => {
47 match iter.extract()? {
48 OrEndOfStream(Some(Either::A(Spanned(span, IdentString(s))))) => {
49 match s.as_str() {
50 "pi" => Ok(Self(value * PI)),
51 "rad" | "radians" => Ok(Self(value)),
52 "deg" | "degrees" => Ok(Self(value * PI / 180.0)),
53 _ => bail!(span, r#"Expected "pi", "rad", "radians", "deg" or "degrees", found {}"#, s)
54 }
55 },
56 OrEndOfStream(Some(Either::B(PunctOf::<'/'>))) => {
57 let Number::<f32>(numer) = iter.extract()?;
58 let LitPi = iter.extract()?;
59 Ok(Self(value / numer * PI))
60 },
61 OrEndOfStream(None) => {
62 Ok(Self(value))
63 }
64 }
65 },
66 Either3::C(PunctOf::<'-'>) => {
67 let angle = Self::from_many(iter.collect())?;
68 Ok(Self(-angle.0))
69 }
70 }
71 }
72
73 fn peek(tt: &proc_macro2::TokenTree) -> bool {
75 match tt {
76 proc_macro2::TokenTree::Group(g) => {
77 g.delimiter() != Delimiter::Brace
78 },
79 _ => true,
80 }
81 }
82}
83
84impl quote::ToTokens for Angle {
85 fn to_tokens(&self, tokens: &mut TokenStream) {
86 self.0.to_tokens(tokens)
87 }
88}