1use crate::{types::TypeInfo, Ownership};
2use heck::*;
3use wit_parser::*;
4
5#[derive(Debug, Copy, Clone, PartialEq)]
6pub enum TypeMode {
7 Owned,
8 AllBorrowed(&'static str),
9}
10
11pub trait RustGenerator<'a> {
12 fn resolve(&self) -> &'a Resolve;
13
14 fn push_str(&mut self, s: &str);
15 fn info(&self, ty: TypeId) -> TypeInfo;
16 fn path_to_interface(&self, interface: InterfaceId) -> Option<String>;
17 fn is_imported_interface(&self, interface: InterfaceId) -> bool;
18 fn wasmtime_path(&self) -> String;
19
20 fn ownership(&self) -> Ownership;
30
31 fn print_ty(&mut self, ty: &Type, mode: TypeMode) {
32 match ty {
33 Type::Id(t) => self.print_tyid(*t, mode),
34 Type::Bool => self.push_str("bool"),
35 Type::U8 => self.push_str("u8"),
36 Type::U16 => self.push_str("u16"),
37 Type::U32 => self.push_str("u32"),
38 Type::U64 => self.push_str("u64"),
39 Type::S8 => self.push_str("i8"),
40 Type::S16 => self.push_str("i16"),
41 Type::S32 => self.push_str("i32"),
42 Type::S64 => self.push_str("i64"),
43 Type::F32 => self.push_str("f32"),
44 Type::F64 => self.push_str("f64"),
45 Type::Char => self.push_str("char"),
46 Type::String => match mode {
47 TypeMode::AllBorrowed(lt) => {
48 self.push_str("&");
49 if lt != "'_" {
50 self.push_str(lt);
51 self.push_str(" ");
52 }
53 self.push_str("str");
54 }
55 TypeMode::Owned => {
56 let wt = self.wasmtime_path();
57 self.push_str(&format!("{wt}::component::__internal::String"))
58 }
59 },
60 Type::ErrorContext => {
61 self.push_str("wasmtime::component::ErrorContext");
62 }
63 }
64 }
65
66 fn print_optional_ty(&mut self, ty: Option<&Type>, mode: TypeMode) {
67 match ty {
68 Some(ty) => self.print_ty(ty, mode),
69 None => self.push_str("()"),
70 }
71 }
72
73 fn print_tyid(&mut self, id: TypeId, mode: TypeMode) {
74 let info = self.info(id);
75 let lt = self.lifetime_for(&info, mode);
76 let ty = &self.resolve().types[id];
77 if ty.name.is_some() {
78 if info.has_list && lt.is_none() {
84 if let TypeMode::AllBorrowed(lt) = mode {
85 self.push_str("&");
86 if lt != "'_" {
87 self.push_str(lt);
88 self.push_str(" ");
89 }
90 }
91 }
92 let name = if lt.is_some() {
93 self.param_name(id)
94 } else {
95 self.result_name(id)
96 };
97 self.print_type_name_in_interface(ty.owner, &name);
98
99 if info.has_list && needs_generics(self.resolve(), &ty.kind) {
103 self.print_generics(lt);
104 }
105
106 return;
107
108 fn needs_generics(resolve: &Resolve, ty: &TypeDefKind) -> bool {
109 match ty {
110 TypeDefKind::Variant(_)
111 | TypeDefKind::Record(_)
112 | TypeDefKind::Option(_)
113 | TypeDefKind::Result(_)
114 | TypeDefKind::Future(_)
115 | TypeDefKind::Stream(_)
116 | TypeDefKind::List(_)
117 | TypeDefKind::Flags(_)
118 | TypeDefKind::Enum(_)
119 | TypeDefKind::Tuple(_)
120 | TypeDefKind::Handle(_)
121 | TypeDefKind::Resource => true,
122 TypeDefKind::Type(Type::Id(t)) => {
123 needs_generics(resolve, &resolve.types[*t].kind)
124 }
125 TypeDefKind::Type(Type::String) => true,
126 TypeDefKind::Type(_) => false,
127 TypeDefKind::Unknown => unreachable!(),
128 }
129 }
130 }
131
132 match &ty.kind {
133 TypeDefKind::List(t) => self.print_list(t, mode),
134
135 TypeDefKind::Option(t) => {
136 self.push_str("Option<");
137 self.print_ty(t, mode);
138 self.push_str(">");
139 }
140
141 TypeDefKind::Result(r) => {
142 self.push_str("Result<");
143 self.print_optional_ty(r.ok.as_ref(), mode);
144 self.push_str(",");
145 self.print_optional_ty(r.err.as_ref(), mode);
146 self.push_str(">");
147 }
148
149 TypeDefKind::Variant(_) => panic!("unsupported anonymous variant"),
150
151 TypeDefKind::Tuple(t) => {
155 self.push_str("(");
156 for ty in t.types.iter() {
157 self.print_ty(ty, mode);
158 self.push_str(",");
159 }
160 self.push_str(")");
161 }
162 TypeDefKind::Record(_) => {
163 panic!("unsupported anonymous type reference: record")
164 }
165 TypeDefKind::Flags(_) => {
166 panic!("unsupported anonymous type reference: flags")
167 }
168 TypeDefKind::Enum(_) => {
169 panic!("unsupported anonymous type reference: enum")
170 }
171 TypeDefKind::Future(ty) => {
172 self.push_str("wasmtime::component::FutureReader<");
173 self.print_optional_ty(ty.as_ref(), TypeMode::Owned);
174 self.push_str(">");
175 }
176 TypeDefKind::Stream(ty) => {
177 self.push_str("wasmtime::component::StreamReader<");
178 self.print_optional_ty(ty.as_ref(), TypeMode::Owned);
179 self.push_str(">");
180 }
181 TypeDefKind::Handle(handle) => {
182 self.print_handle(handle);
183 }
184 TypeDefKind::Resource => unreachable!(),
185
186 TypeDefKind::Type(t) => self.print_ty(t, mode),
187 TypeDefKind::Unknown => unreachable!(),
188 }
189 }
190
191 fn print_type_name_in_interface(&mut self, owner: TypeOwner, name: &str) {
192 if let TypeOwner::Interface(id) = owner {
193 if let Some(path) = self.path_to_interface(id) {
194 self.push_str(&path);
195 self.push_str("::");
196 }
197 }
198 self.push_str(name);
199 }
200
201 fn print_list(&mut self, ty: &Type, mode: TypeMode) {
202 let next_mode = if matches!(self.ownership(), Ownership::Owning) {
203 TypeMode::Owned
204 } else {
205 mode
206 };
207 match mode {
208 TypeMode::AllBorrowed(lt) => {
209 self.push_str("&");
210 if lt != "'_" {
211 self.push_str(lt);
212 self.push_str(" ");
213 }
214 self.push_str("[");
215 self.print_ty(ty, next_mode);
216 self.push_str("]");
217 }
218 TypeMode::Owned => {
219 let wt = self.wasmtime_path();
220 self.push_str(&format!("{wt}::component::__internal::Vec<"));
221 self.print_ty(ty, next_mode);
222 self.push_str(">");
223 }
224 }
225 }
226
227 fn print_stream(&mut self, ty: Option<&Type>) {
228 let wt = self.wasmtime_path();
229 self.push_str(&format!("{wt}::component::StreamReader<"));
230 self.print_optional_ty(ty, TypeMode::Owned);
231 self.push_str(">");
232 }
233
234 fn print_future(&mut self, ty: Option<&Type>) {
235 let wt = self.wasmtime_path();
236 self.push_str(&format!("{wt}::component::FutureReader<"));
237 self.print_optional_ty(ty, TypeMode::Owned);
238 self.push_str(">");
239 }
240
241 fn print_handle(&mut self, handle: &Handle) {
242 let resource = match handle {
255 Handle::Own(t) | Handle::Borrow(t) => *t,
256 };
257 let ty = &self.resolve().types[resource];
258 let def_id = super::resolve_type_definition_id(self.resolve(), resource);
259 let ty_def = &self.resolve().types[def_id];
260 let is_host_defined = match ty_def.owner {
261 TypeOwner::Interface(i) => self.is_imported_interface(i),
262 _ => true,
263 };
264 let wt = self.wasmtime_path();
265 if is_host_defined {
266 self.push_str(&format!("{wt}::component::Resource<"));
267 self.print_type_name_in_interface(
268 ty.owner,
269 &ty.name.as_ref().unwrap().to_upper_camel_case(),
270 );
271 self.push_str(">");
272 } else {
273 self.push_str(&format!("{wt}::component::ResourceAny"));
274 }
275 }
276
277 fn print_generics(&mut self, lifetime: Option<&str>) {
278 if lifetime.is_none() {
279 return;
280 }
281 self.push_str("<");
282 if let Some(lt) = lifetime {
283 self.push_str(lt);
284 self.push_str(",");
285 }
286 self.push_str(">");
287 }
288
289 fn modes_of(&self, ty: TypeId) -> Vec<(String, TypeMode)> {
290 let info = self.info(ty);
291 if !info.owned && !info.borrowed {
294 return vec![(
295 self.param_name(ty),
296 match self.ownership() {
297 Ownership::Owning => TypeMode::Owned,
298 Ownership::Borrowing { .. } => TypeMode::AllBorrowed("'a"),
299 },
300 )];
301 }
302 let mut result = Vec::new();
303 let first_mode =
304 if info.owned || !info.borrowed || matches!(self.ownership(), Ownership::Owning) {
305 TypeMode::Owned
306 } else {
307 assert!(!self.uses_two_names(&info));
308 TypeMode::AllBorrowed("'a")
309 };
310 result.push((self.result_name(ty), first_mode));
311 if self.uses_two_names(&info) {
312 result.push((self.param_name(ty), TypeMode::AllBorrowed("'a")));
313 }
314 result
315 }
316
317 fn param_name(&self, ty: TypeId) -> String {
318 let info = self.info(ty);
319 let name = self.resolve().types[ty]
320 .name
321 .as_ref()
322 .unwrap()
323 .to_upper_camel_case();
324 if self.uses_two_names(&info) {
325 format!("{name}Param")
326 } else {
327 name
328 }
329 }
330
331 fn result_name(&self, ty: TypeId) -> String {
332 let info = self.info(ty);
333 let name = self.resolve().types[ty]
334 .name
335 .as_ref()
336 .unwrap()
337 .to_upper_camel_case();
338 if self.uses_two_names(&info) {
339 format!("{name}Result")
340 } else {
341 name
342 }
343 }
344
345 fn uses_two_names(&self, info: &TypeInfo) -> bool {
346 info.has_list
347 && info.borrowed
348 && info.owned
349 && matches!(
350 self.ownership(),
351 Ownership::Borrowing {
352 duplicate_if_necessary: true
353 }
354 )
355 }
356
357 fn lifetime_for(&self, info: &TypeInfo, mode: TypeMode) -> Option<&'static str> {
358 if matches!(self.ownership(), Ownership::Owning) {
359 return None;
360 }
361 let lt = match mode {
362 TypeMode::AllBorrowed(s) => s,
363 _ => return None,
364 };
365 if !info.has_list {
367 return None;
368 }
369 if self.uses_two_names(info) || (info.borrowed && !info.owned) {
375 Some(lt)
376 } else {
377 None
378 }
379 }
380}
381
382pub fn to_rust_ident(name: &str) -> String {
384 match name {
385 "as" => "as_".into(),
388 "break" => "break_".into(),
389 "const" => "const_".into(),
390 "continue" => "continue_".into(),
391 "crate" => "crate_".into(),
392 "else" => "else_".into(),
393 "enum" => "enum_".into(),
394 "extern" => "extern_".into(),
395 "false" => "false_".into(),
396 "fn" => "fn_".into(),
397 "for" => "for_".into(),
398 "if" => "if_".into(),
399 "impl" => "impl_".into(),
400 "in" => "in_".into(),
401 "let" => "let_".into(),
402 "loop" => "loop_".into(),
403 "match" => "match_".into(),
404 "mod" => "mod_".into(),
405 "move" => "move_".into(),
406 "mut" => "mut_".into(),
407 "pub" => "pub_".into(),
408 "ref" => "ref_".into(),
409 "return" => "return_".into(),
410 "self" => "self_".into(),
411 "static" => "static_".into(),
412 "struct" => "struct_".into(),
413 "super" => "super_".into(),
414 "trait" => "trait_".into(),
415 "true" => "true_".into(),
416 "type" => "type_".into(),
417 "unsafe" => "unsafe_".into(),
418 "use" => "use_".into(),
419 "where" => "where_".into(),
420 "while" => "while_".into(),
421 "async" => "async_".into(),
422 "await" => "await_".into(),
423 "dyn" => "dyn_".into(),
424 "abstract" => "abstract_".into(),
425 "become" => "become_".into(),
426 "box" => "box_".into(),
427 "do" => "do_".into(),
428 "final" => "final_".into(),
429 "macro" => "macro_".into(),
430 "override" => "override_".into(),
431 "priv" => "priv_".into(),
432 "typeof" => "typeof_".into(),
433 "unsized" => "unsized_".into(),
434 "virtual" => "virtual_".into(),
435 "yield" => "yield_".into(),
436 "try" => "try_".into(),
437 "gen" => "gen_".into(),
438 s => s.to_snake_case(),
439 }
440}
441
442pub fn to_rust_upper_camel_case(name: &str) -> String {
444 match name {
445 "host" => "Host_".into(),
448 s => s.to_upper_camel_case(),
449 }
450}