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}