witx_codegen/rust/
mod.rs

1mod common;
2mod function;
3mod header;
4mod r#struct;
5mod tuple;
6mod union;
7
8use std::io::Write;
9
10use common::*;
11
12use super::*;
13use crate::astype::*;
14use crate::error::*;
15use crate::pretty_writer::PrettyWriter;
16
17pub struct RustGenerator {
18    module_name: Option<String>,
19}
20
21impl RustGenerator {
22    pub fn new(module_name: Option<String>) -> Self {
23        RustGenerator { module_name }
24    }
25}
26
27impl<T: Write> Generator<T> for RustGenerator {
28    fn generate(
29        &self,
30        writer: &mut T,
31        module_witx: witx::Module,
32        options: &Options,
33    ) -> Result<(), Error> {
34        let mut w = PrettyWriter::new(writer, "    ");
35        let module_name = match &self.module_name {
36            None => module_witx.name().as_str().to_string(),
37            Some(module_name) => module_name.to_string(),
38        };
39        let module_id = module_witx.module_id();
40        let skip_imports = options.skip_imports;
41
42        if !options.skip_header {
43            Self::header(&mut w)?;
44        }
45
46        let module_title_comments = format!(
47            "---------------------- Module: [{}] ----------------------",
48            module_name
49        );
50        Self::write_comments(&mut w, &module_title_comments)?;
51        w.eob()?;
52
53        for type_ in module_witx.typenames() {
54            if skip_imports && &type_.module != module_id {
55                continue;
56            }
57            let constants_for_type: Vec<_> = module_witx
58                .constants()
59                .filter_map(|x| {
60                    if x.ty == type_.name {
61                        Some(ASConstant {
62                            name: x.name.as_str().to_string(),
63                            value: x.value,
64                        })
65                    } else {
66                        None
67                    }
68                })
69                .collect();
70            Self::define_type(&mut w, type_.as_ref(), &constants_for_type)?;
71        }
72
73        for func in module_witx.funcs() {
74            Self::define_func(&mut w, &module_name, func.as_ref())?;
75        }
76
77        Ok(())
78    }
79}
80
81impl RustGenerator {
82    fn write_docs<T: Write>(w: &mut PrettyWriter<T>, docs: &str) -> Result<(), Error> {
83        if docs.is_empty() {
84            return Ok(());
85        }
86        for docs_line in docs.lines() {
87            w.write_line(format!("/// {}", docs_line))?;
88        }
89        Ok(())
90    }
91
92    fn write_comments<T: Write>(w: &mut PrettyWriter<T>, docs: &str) -> Result<(), Error> {
93        if docs.is_empty() {
94            return Ok(());
95        }
96        for docs_line in docs.lines() {
97            w.write_line(format!("// {}", docs_line))?;
98        }
99        Ok(())
100    }
101
102    fn define_as_alias<T: Write>(
103        w: &mut PrettyWriter<T>,
104        name: &str,
105        other_type: &ASType,
106    ) -> Result<(), Error> {
107        w.write_line(format!(
108            "pub type {} = {};",
109            name.as_type(),
110            other_type.as_lang()
111        ))?;
112        Ok(())
113    }
114
115    fn define_as_atom<T: Write>(
116        w: &mut PrettyWriter<T>,
117        name: &str,
118        type_: &ASType,
119    ) -> Result<(), Error> {
120        w.write_line(format!(
121            "pub type {} = {};",
122            name.as_type(),
123            type_.as_lang()
124        ))?;
125        Ok(())
126    }
127
128    fn define_as_enum<T: Write>(
129        w: &mut PrettyWriter<T>,
130        name: &str,
131        enum_: &ASEnum,
132    ) -> Result<(), Error> {
133        let repr = enum_.repr.as_ref();
134        w.write_line(format!("pub type {} = {};", name.as_type(), repr.as_lang()))?;
135        w.eob()?;
136        w.write_line("#[allow(non_snake_case)]")?;
137        w.write_line(format!("pub mod {} {{", name.as_namespace()))?;
138        {
139            let mut w = w.new_block();
140            w.write_line(format!("use super::{};", name.as_type()))?;
141            for choice in &enum_.choices {
142                w.write_line(format!(
143                    "pub const {}: {} = {};",
144                    choice.name.as_const(),
145                    name.as_type(),
146                    choice.value
147                ))?;
148            }
149        }
150        w.write_line("}")?;
151        Ok(())
152    }
153
154    fn define_as_constants<T: Write>(
155        w: &mut PrettyWriter<T>,
156        name: &str,
157        constants: &ASConstants,
158    ) -> Result<(), Error> {
159        let repr = constants.repr.as_ref();
160        w.write_line(format!("pub type {} = {};", name.as_type(), repr.as_lang()))?;
161        w.eob()?;
162        Self::define_constants_for_type(w, name, &constants.constants)?;
163        Ok(())
164    }
165
166    fn define_as_type<T: Write>(
167        w: &mut PrettyWriter<T>,
168        name: &str,
169        type_: &ASType,
170    ) -> Result<(), Error> {
171        match type_ {
172            ASType::Alias(_)
173            | ASType::Bool
174            | ASType::Char8
175            | ASType::Char32
176            | ASType::F32
177            | ASType::F64
178            | ASType::U8
179            | ASType::U16
180            | ASType::U32
181            | ASType::U64
182            | ASType::S8
183            | ASType::S16
184            | ASType::S32
185            | ASType::S64
186            | ASType::USize
187            | ASType::Handle(_)
188            | ASType::Slice(_)
189            | ASType::String(_)
190            | ASType::ReadBuffer(_)
191            | ASType::WriteBuffer(_) => Self::define_as_atom(w, name, type_)?,
192            ASType::Enum(enum_) => Self::define_as_enum(w, name, enum_)?,
193            ASType::Union(union_) => Self::define_as_union(w, name, union_)?,
194            ASType::Constants(constants) => Self::define_as_constants(w, name, constants)?,
195            ASType::Tuple(members) => Self::define_as_tuple(w, name, members)?,
196            ASType::Struct(members) => Self::define_as_struct(w, name, members)?,
197            _ => {
198                dbg!(type_);
199                unimplemented!();
200            }
201        }
202        Ok(())
203    }
204
205    fn define_constants_for_type<T: Write>(
206        w: &mut PrettyWriter<T>,
207        type_name: &str,
208        constants: &[ASConstant],
209    ) -> Result<(), Error> {
210        if constants.is_empty() {
211            return Ok(());
212        }
213        w.write_line("#[allow(non_snake_case)]")?;
214        w.write_line(format!("pub mod {} {{", type_name.as_namespace()))?;
215        {
216            let mut w = w.new_block();
217            w.write_line(format!("use super::{};", type_name.as_type()))?;
218
219            let mut hex = false;
220            let mut single_bits: usize = 0;
221            for constant in constants {
222                if constant.value > 0xffff {
223                    hex = true;
224                }
225                if constant.value.count_ones() == 1 {
226                    single_bits += 1;
227                }
228            }
229            if constants.len() > 2 && single_bits == constants.len() {
230                hex = true;
231            }
232            for constant in constants {
233                let value_s = if hex {
234                    format!("0x{:x}", constant.value)
235                } else {
236                    format!("{}", constant.value)
237                };
238                w.write_line(format!(
239                    "pub const {}: {} = {};",
240                    constant.name.as_const(),
241                    type_name.as_type(),
242                    value_s
243                ))?;
244            }
245        }
246        w.write_line("}")?;
247        w.eob()?;
248        Ok(())
249    }
250
251    fn define_type<T: Write>(
252        w: &mut PrettyWriter<T>,
253        type_witx: &witx::NamedType,
254        constants: &[ASConstant],
255    ) -> Result<(), Error> {
256        let docs = &type_witx.docs;
257        if !docs.is_empty() {
258            Self::write_docs(w, docs)?;
259        }
260        let type_name = type_witx.name.as_str();
261        let tref = &type_witx.tref;
262        match tref {
263            witx::TypeRef::Name(other_type) => {
264                Self::define_as_alias(w, type_name, &ASType::from(&other_type.tref))?
265            }
266            witx::TypeRef::Value(type_witx) => {
267                let t = ASType::from(type_witx.as_ref());
268                Self::define_as_type(w, type_name, &t)?
269            }
270        }
271        w.eob()?;
272        Self::define_constants_for_type(w, type_name, constants)?;
273        Ok(())
274    }
275}