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) -> &'a Enum {
55    protocol
56        .interfaces
57        .iter()
58        .find_map(|interface| interface.enums.iter().find(|e| e.name == name))
59        .unwrap()
60}
61
62pub fn write_enums(interface: &Interface) -> Vec<TokenStream> {
63    let mut enums = Vec::new();
64
65    for e in &interface.enums {
66        let docs = description_to_docs(e.description.as_ref());
67        let name = make_ident(e.name.to_upper_camel_case());
68
69        if !e.bitfield {
70            let mut variants = Vec::new();
71            let mut match_variants = Vec::new();
72
73            for entry in &e.entries {
74                let docs = description_to_docs(entry.summary.as_ref());
75                let name = make_ident(entry.name.to_upper_camel_case());
76                let value = value_to_u32(&entry.value);
77
78                variants.push(quote! {
79                    #(#docs)*
80                    #name = #value
81                });
82
83                match_variants.push(quote! { #value => { Ok(Self::#name) } });
84            }
85
86            enums.push(quote! {
87                #(#docs)*
88                #[repr(u32)]
89                #[non_exhaustive]
90                #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
91                pub enum #name {
92                    #(#variants),*
93                }
94
95                impl TryFrom<u32> for #name {
96                    type Error = crate::wire::DecodeError;
97
98                    fn try_from(v: u32) -> Result<Self, Self::Error> {
99                        match v {
100                            #(#match_variants),*
101                            _ => Err(crate::wire::DecodeError::MalformedPayload)
102                        }
103                    }
104                }
105
106                impl std::fmt::Display for #name {
107                    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
108                        (*self as u32).fmt(f)
109                    }
110                }
111            })
112        } else {
113            let mut variants = Vec::new();
114
115            for entry in &e.entries {
116                let name = make_ident(entry.name.to_upper_camel_case());
117
118                let docs = description_to_docs(entry.summary.as_ref());
119
120                let value = value_to_u32(&entry.value);
121
122                variants.push(quote! {
123                    #(#docs)*
124                    const #name = #value;
125                });
126            }
127
128            enums.push(quote! {
129                bitflags::bitflags! {
130                    #(#docs)*
131                    #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
132                    pub struct #name: u32 {
133                        #(#variants)*
134                    }
135                }
136
137                impl TryFrom<u32> for #name {
138                    type Error = crate::wire::DecodeError;
139
140                    fn try_from(v: u32) -> Result<Self, Self::Error> {
141                       Self::from_bits(v).ok_or(crate::wire::DecodeError::MalformedPayload)
142                    }
143                }
144
145                impl std::fmt::Display for #name {
146                    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
147                        self.bits().fmt(f)
148                    }
149                }
150            })
151        }
152    }
153
154    enums
155}