witx_codegen/rust/
common.rs

1use convert_case::{Case, Casing};
2
3use super::tuple::Tuple;
4use crate::astype::*;
5
6pub trait IsNullable {
7    fn is_nullable(&self) -> bool;
8}
9
10impl IsNullable for ASType {
11    fn is_nullable(&self) -> bool {
12        matches!(
13            self,
14            ASType::ConstPtr(_)
15                | ASType::MutPtr(_)
16                | ASType::ReadBuffer(_)
17                | ASType::WriteBuffer(_)
18                | ASType::Enum(_)
19                | ASType::Struct(_)
20                | ASType::Tuple(_)
21                | ASType::Union(_)
22        )
23    }
24}
25
26pub trait Normalize {
27    fn as_str(&self) -> &str;
28
29    fn as_type(&self) -> String {
30        self.as_str().to_case(Case::Pascal)
31    }
32
33    fn as_fn(&self) -> String {
34        escape_reserved_word(&self.as_str().to_case(Case::Snake))
35    }
36
37    fn as_fn_suffix(&self) -> String {
38        escape_reserved_word(&self.as_str().to_case(Case::Snake))
39    }
40
41    fn as_var(&self) -> String {
42        escape_reserved_word(&self.as_str().to_case(Case::Snake))
43    }
44
45    fn as_const(&self) -> String {
46        self.as_str().to_case(Case::UpperSnake)
47    }
48
49    fn as_namespace(&self) -> String {
50        self.as_str().to_string().to_case(Case::UpperSnake)
51    }
52}
53
54impl<T: AsRef<str>> Normalize for T {
55    fn as_str(&self) -> &str {
56        self.as_ref()
57    }
58}
59
60pub trait ToLanguageRepresentation {
61    fn as_astype(&self) -> &ASType;
62
63    fn to_string(&self) -> String {
64        self.as_lang()
65    }
66
67    fn as_lang(&self) -> String {
68        match self.as_astype() {
69            ASType::Alias(alias) => alias.name.as_type(),
70            ASType::Bool => "bool".to_string(),
71            ASType::Char32 => "Char32".to_string(),
72            ASType::Char8 => "Char8".to_string(),
73            ASType::F32 => "f32".to_string(),
74            ASType::F64 => "f64".to_string(),
75            ASType::Handle(_resource_name) => "WasiHandle".to_string(),
76            ASType::ConstPtr(pointee) => format!("WasiPtr<{}>", pointee.to_string()),
77            ASType::MutPtr(pointee) => format!("WasiMutPtr<{}>", pointee.to_string()),
78            ASType::Option(_) => todo!(),
79            ASType::Result(_) => todo!(),
80            ASType::S8 => "i8".to_string(),
81            ASType::S16 => "i16".to_string(),
82            ASType::S32 => "i32".to_string(),
83            ASType::S64 => "i64".to_string(),
84            ASType::U8 => "u8".to_string(),
85            ASType::U16 => "u16".to_string(),
86            ASType::U32 => "u32".to_string(),
87            ASType::U64 => "u64".to_string(),
88            ASType::USize => "usize".to_string(),
89            ASType::Void => "()".to_string(),
90            ASType::Constants(_) => unimplemented!(),
91            ASType::Enum(enum_) => {
92                format!("{} /* Enum */", enum_.repr.as_ref().as_lang())
93            }
94            ASType::Struct(_) => unimplemented!(),
95            ASType::Tuple(tuple_members) => Tuple::name_for(tuple_members).as_type(),
96            ASType::Union(_) => unimplemented!(),
97            ASType::Slice(element_type) => format!("WasiMutSlice<{}>", element_type.as_lang()),
98            ASType::String(_) => "WasiString".to_string(),
99            ASType::ReadBuffer(element_type) => format!("WasiSlice<{}>", element_type.as_lang()),
100            ASType::WriteBuffer(element_type) => {
101                format!("WasiMutSlice<{}>", element_type.to_string())
102            }
103        }
104    }
105}
106
107impl ToLanguageRepresentation for ASType {
108    fn as_astype(&self) -> &ASType {
109        self
110    }
111}
112
113/// Checks the given word against a list of reserved keywords.
114/// If the given word conflicts with a keyword, a trailing underscore will be
115/// appended.
116///
117/// Adapted from [wiggle](https://docs.rs/wiggle/latest/wiggle/index.html)
118pub fn escape_reserved_word(word: &str) -> String {
119    if STRICT.iter().chain(RESERVED).any(|k| *k == word) {
120        // If the camel-cased string matched any strict or reserved keywords, then
121        // append a trailing underscore to the identifier we generate.
122        format!("{}_", word)
123    } else {
124        word.to_string() // Otherwise, use the string as is.
125    }
126}
127
128/// Strict keywords.
129///
130/// Source: [The Rust Reference][https://doc.rust-lang.org/reference/keywords.html#strict-keywords]
131const STRICT: &[&str] = &[
132    "as", "async", "await", "break", "const", "continue", "crate", "dyn", "else", "enum", "extern",
133    "false", "fn", "for", "if", "impl", "in", "let", "loop", "match", "mod", "move", "mut", "pub",
134    "ref", "return", "self", "Self", "static", "struct", "super", "trait", "true", "type",
135    "unsafe", "use", "where", "while",
136];
137
138/// Reserved keywords.
139///
140/// These keywords aren't used yet, but they are reserved for future use. They
141/// have the same restrictions as strict keywords. The reasoning behind this is
142/// to make current programs forward compatible with future versions of Rust by
143/// forbidding them to use these keywords.
144///
145/// Source: [The Rust Reference](https://doc.rust-lang.org/reference/keywords.html#reserved-keywords)
146const RESERVED: &[&str] = &[
147    "abstract", "become", "box", "do", "final", "macro", "override", "priv", "try", "typeof",
148    "unsized", "virtual", "yield",
149];