waynest_gen/
utils.rs

1use heck::ToUpperCamelCase;
2use proc_macro2::{Ident, TokenStream};
3use quote::{format_ident, quote};
4use std::fmt::Display;
5
6use crate::parser::{Enum, Interface, Protocol};
7
8const KEYWORDS: [&str; 52] = [
9    "as", "break", "const", "continue", "crate", "else", "enum", "extern", "false", "fn", "for",
10    "if", "impl", "in", "let", "loop", "match", "mod", "move", "mut", "pub", "ref", "return",
11    "self", "Self", "static", "struct", "super", "trait", "true", "type", "unsafe", "use", "where",
12    "while", "async", "await", "dyn", "abstract", "become", "box", "do", "final", "macro",
13    "override", "priv", "typeof", "unsized", "virtual", "yield", "try", "gen",
14];
15
16pub fn description_to_docs(description: Option<&String>) -> Vec<TokenStream> {
17    let mut docs = Vec::new();
18
19    if let Some(description) = description {
20        for line in description.lines() {
21            // writeln!(&mut generated_path, r##"#[doc = r#"{}"#]"##, line.trim())?;
22            let doc = line.trim();
23            docs.push(quote! {#[doc = #doc]})
24        }
25    }
26
27    docs
28}
29
30pub fn value_to_u32(value: &str) -> u32 {
31    if let Some(s) = value.strip_prefix("0x") {
32        u32::from_str_radix(s, 16).expect("Invalid enum value")
33    } else {
34        value.parse().expect("Invalid enum value")
35    }
36}
37
38pub fn make_ident<D: Display>(ident: D) -> Ident {
39    let mut prefix = "";
40
41    if ident.to_string().chars().next().unwrap().is_numeric() {
42        prefix = "_"
43    }
44
45    let mut raw: &str = "";
46
47    if KEYWORDS.contains(&ident.to_string().as_str()) {
48        raw = "r#"
49    }
50
51    format_ident!("{raw}{prefix}{ident}")
52}
53
54pub fn find_enum<'a>(protocol: &'a Protocol, name: &str) -> Option<&'a Enum> {
55    protocol
56        .interfaces
57        .iter()
58        .find_map(|interface| interface.enums.iter().find(|e| e.name == name))
59}
60
61pub fn write_enums(interface: &Interface) -> Vec<TokenStream> {
62    let mut enums = Vec::new();
63
64    for e in &interface.enums {
65        let docs = description_to_docs(e.description.as_ref());
66        let name = make_ident(e.name.to_upper_camel_case());
67
68        if !e.bitfield {
69            let mut variants = Vec::new();
70            let mut match_variants = Vec::new();
71
72            for entry in &e.entries {
73                let docs = description_to_docs(entry.summary.as_ref());
74                let name = make_ident(entry.name.to_upper_camel_case());
75                let value = value_to_u32(&entry.value);
76
77                variants.push(quote! {
78                    #(#docs)*
79                    #name = #value
80                });
81
82                match_variants.push(quote! { #value => { Ok(Self::#name) } });
83            }
84
85            enums.push(quote! {
86                #(#docs)*
87                #[repr(u32)]
88                #[non_exhaustive]
89                #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
90                pub enum #name {
91                    #(#variants),*
92                }
93
94                impl TryFrom<u32> for #name {
95                    type Error = crate::wire::DecodeError;
96
97                    fn try_from(v: u32) -> Result<Self, Self::Error> {
98                        match v {
99                            #(#match_variants),*
100                            _ => Err(crate::wire::DecodeError::MalformedPayload)
101                        }
102                    }
103                }
104
105                impl std::fmt::Display for #name {
106                    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
107                        (*self as u32).fmt(f)
108                    }
109                }
110            })
111        } else {
112            let mut variants = Vec::new();
113
114            for entry in &e.entries {
115                let name = make_ident(entry.name.to_upper_camel_case());
116
117                let docs = description_to_docs(entry.summary.as_ref());
118
119                let value = value_to_u32(&entry.value);
120
121                variants.push(quote! {
122                    #(#docs)*
123                    const #name = #value;
124                });
125            }
126
127            enums.push(quote! {
128                bitflags::bitflags! {
129                    #(#docs)*
130                    #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
131                    pub struct #name: u32 {
132                        #(#variants)*
133                    }
134                }
135
136                impl TryFrom<u32> for #name {
137                    type Error = crate::wire::DecodeError;
138
139                    fn try_from(v: u32) -> Result<Self, Self::Error> {
140                       Self::from_bits(v).ok_or(crate::wire::DecodeError::MalformedPayload)
141                    }
142                }
143
144                impl std::fmt::Display for #name {
145                    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
146                        self.bits().fmt(f)
147                    }
148                }
149            })
150        }
151    }
152
153    enums
154}