1use crate::{Ownership, types::TypeInfo};
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 self.push_str(&self.ty(ty, mode))
33 }
34 fn ty(&self, ty: &Type, mode: TypeMode) -> String {
35 match ty {
36 Type::Id(t) => self.tyid(*t, mode),
37 Type::Bool => "bool".to_string(),
38 Type::U8 => "u8".to_string(),
39 Type::U16 => "u16".to_string(),
40 Type::U32 => "u32".to_string(),
41 Type::U64 => "u64".to_string(),
42 Type::S8 => "i8".to_string(),
43 Type::S16 => "i16".to_string(),
44 Type::S32 => "i32".to_string(),
45 Type::S64 => "i64".to_string(),
46 Type::F32 => "f32".to_string(),
47 Type::F64 => "f64".to_string(),
48 Type::Char => "char".to_string(),
49 Type::String => match mode {
50 TypeMode::AllBorrowed(lt) => {
51 if lt != "'_" {
52 format!("&{lt} str")
53 } else {
54 format!("&str")
55 }
56 }
57 TypeMode::Owned => {
58 let wt = self.wasmtime_path();
59 format!("{wt}::component::__internal::String")
60 }
61 },
62 Type::ErrorContext => {
63 let wt = self.wasmtime_path();
64 format!("{wt}::component::ErrorContext")
65 }
66 }
67 }
68
69 fn print_optional_ty(&mut self, ty: Option<&Type>, mode: TypeMode) {
70 self.push_str(&self.optional_ty(ty, mode))
71 }
72 fn optional_ty(&self, ty: Option<&Type>, mode: TypeMode) -> String {
73 match ty {
74 Some(ty) => self.ty(ty, mode),
75 None => "()".to_string(),
76 }
77 }
78
79 fn tyid(&self, id: TypeId, mode: TypeMode) -> String {
80 let info = self.info(id);
81 let lt = self.lifetime_for(&info, mode);
82 let ty = &self.resolve().types[id];
83 if ty.name.is_some() {
84 let mut out = String::new();
90 if info.has_list && lt.is_none() {
91 if let TypeMode::AllBorrowed(lt) = mode {
92 if lt != "'_" {
93 out.push_str(&format!("&{lt} "))
94 } else {
95 out.push_str("&")
96 }
97 }
98 }
99 let name = if lt.is_some() {
100 self.param_name(id)
101 } else {
102 self.result_name(id)
103 };
104 out.push_str(&self.type_name_in_interface(ty.owner, &name));
105
106 if info.has_list && needs_generics(self.resolve(), &ty.kind) {
110 out.push_str(&self.generics(lt));
111 }
112
113 return out;
114
115 fn needs_generics(resolve: &Resolve, ty: &TypeDefKind) -> bool {
116 match ty {
117 TypeDefKind::Variant(_)
118 | TypeDefKind::Record(_)
119 | TypeDefKind::Option(_)
120 | TypeDefKind::Result(_)
121 | TypeDefKind::Future(_)
122 | TypeDefKind::Stream(_)
123 | TypeDefKind::List(_)
124 | TypeDefKind::Flags(_)
125 | TypeDefKind::Enum(_)
126 | TypeDefKind::Tuple(_)
127 | TypeDefKind::Handle(_)
128 | TypeDefKind::Resource => true,
129 TypeDefKind::Type(Type::Id(t)) => {
130 needs_generics(resolve, &resolve.types[*t].kind)
131 }
132 TypeDefKind::Type(Type::String) => true,
133 TypeDefKind::Type(_) => false,
134 TypeDefKind::Unknown => unreachable!(),
135 TypeDefKind::FixedSizeList(..) => todo!(),
136 }
137 }
138 }
139
140 match &ty.kind {
141 TypeDefKind::List(t) => self.list(t, mode),
142
143 TypeDefKind::Option(t) => {
144 format!("Option<{}>", self.ty(t, mode))
145 }
146
147 TypeDefKind::Result(r) => {
148 let ok = self.optional_ty(r.ok.as_ref(), mode);
149 let err = self.optional_ty(r.err.as_ref(), mode);
150 format!("Result<{ok},{err}>")
151 }
152
153 TypeDefKind::Variant(_) => panic!("unsupported anonymous variant"),
154
155 TypeDefKind::Tuple(t) => {
159 let mut out = "(".to_string();
160 for ty in t.types.iter() {
161 out.push_str(&self.ty(ty, mode));
162 out.push_str(",");
163 }
164 out.push_str(")");
165 out
166 }
167 TypeDefKind::Record(_) => {
168 panic!("unsupported anonymous type reference: record")
169 }
170 TypeDefKind::Flags(_) => {
171 panic!("unsupported anonymous type reference: flags")
172 }
173 TypeDefKind::Enum(_) => {
174 panic!("unsupported anonymous type reference: enum")
175 }
176 TypeDefKind::Future(ty) => {
177 let wt = self.wasmtime_path();
178 let t = self.optional_ty(ty.as_ref(), TypeMode::Owned);
179 format!("{wt}::component::HostFuture<{t}>")
180 }
181 TypeDefKind::Stream(ty) => {
182 let wt = self.wasmtime_path();
183 let t = self.optional_ty(ty.as_ref(), TypeMode::Owned);
184 format!("{wt}::component::HostStream<{t}>")
185 }
186 TypeDefKind::Handle(handle) => self.handle(handle),
187 TypeDefKind::Resource => unreachable!(),
188
189 TypeDefKind::Type(t) => self.ty(t, mode),
190 TypeDefKind::Unknown => unreachable!(),
191 TypeDefKind::FixedSizeList(..) => todo!(),
192 }
193 }
194
195 fn type_name_in_interface(&self, owner: TypeOwner, name: &str) -> String {
196 let mut out = String::new();
197 if let TypeOwner::Interface(id) = owner {
198 if let Some(path) = self.path_to_interface(id) {
199 out.push_str(&path);
200 out.push_str("::");
201 }
202 }
203 out.push_str(name);
204 out
205 }
206
207 fn print_list(&mut self, ty: &Type, mode: TypeMode) {
208 self.push_str(&self.list(ty, mode))
209 }
210 fn list(&self, ty: &Type, mode: TypeMode) -> String {
211 let next_mode = if matches!(self.ownership(), Ownership::Owning) {
212 TypeMode::Owned
213 } else {
214 mode
215 };
216 let ty = self.ty(ty, next_mode);
217 match mode {
218 TypeMode::AllBorrowed(lt) => {
219 if lt != "'_" {
220 format!("&{lt} [{ty}]")
221 } else {
222 format!("&[{ty}]")
223 }
224 }
225 TypeMode::Owned => {
226 let wt = self.wasmtime_path();
227 format!("{wt}::component::__internal::Vec<{ty}>")
228 }
229 }
230 }
231
232 fn print_stream(&mut self, ty: Option<&Type>) {
233 self.push_str(&self.stream(ty))
234 }
235 fn stream(&self, ty: Option<&Type>) -> String {
236 let wt = self.wasmtime_path();
237 let mut out = format!("{wt}::component::HostStream<");
238 out.push_str(&self.optional_ty(ty, TypeMode::Owned));
239 out.push_str(">");
240 out
241 }
242
243 fn print_future(&mut self, ty: Option<&Type>) {
244 self.push_str(&self.future(ty))
245 }
246 fn future(&self, ty: Option<&Type>) -> String {
247 let wt = self.wasmtime_path();
248 let mut out = format!("{wt}::component::HostFuture<");
249 out.push_str(&self.optional_ty(ty, TypeMode::Owned));
250 out.push_str(">");
251 out
252 }
253
254 fn print_handle(&mut self, handle: &Handle) {
255 self.push_str(&self.handle(handle))
256 }
257 fn handle(&self, handle: &Handle) -> String {
258 let resource = match handle {
271 Handle::Own(t) | Handle::Borrow(t) => *t,
272 };
273 let ty = &self.resolve().types[resource];
274 let def_id = super::resolve_type_definition_id(self.resolve(), resource);
275 let ty_def = &self.resolve().types[def_id];
276 let is_host_defined = match ty_def.owner {
277 TypeOwner::Interface(i) => self.is_imported_interface(i),
278 _ => true,
279 };
280 let wt = self.wasmtime_path();
281 if is_host_defined {
282 let mut out = format!("{wt}::component::Resource<");
283 out.push_str(&self.type_name_in_interface(
284 ty.owner,
285 &ty.name.as_ref().unwrap().to_upper_camel_case(),
286 ));
287 out.push_str(">");
288 out
289 } else {
290 format!("{wt}::component::ResourceAny")
291 }
292 }
293
294 fn print_generics(&mut self, lifetime: Option<&str>) {
295 self.push_str(&self.generics(lifetime))
296 }
297 fn generics(&self, lifetime: Option<&str>) -> String {
298 if let Some(lt) = lifetime {
299 format!("<{lt},>")
300 } else {
301 String::new()
302 }
303 }
304
305 fn modes_of(&self, ty: TypeId) -> Vec<(String, TypeMode)> {
306 let info = self.info(ty);
307 if !info.owned && !info.borrowed {
310 return vec![(
311 self.param_name(ty),
312 match self.ownership() {
313 Ownership::Owning => TypeMode::Owned,
314 Ownership::Borrowing { .. } => TypeMode::AllBorrowed("'a"),
315 },
316 )];
317 }
318 let mut result = Vec::new();
319 let first_mode =
320 if info.owned || !info.borrowed || matches!(self.ownership(), Ownership::Owning) {
321 TypeMode::Owned
322 } else {
323 assert!(!self.uses_two_names(&info));
324 TypeMode::AllBorrowed("'a")
325 };
326 result.push((self.result_name(ty), first_mode));
327 if self.uses_two_names(&info) {
328 result.push((self.param_name(ty), TypeMode::AllBorrowed("'a")));
329 }
330 result
331 }
332
333 fn param_name(&self, ty: TypeId) -> String {
334 let info = self.info(ty);
335 let name = self.resolve().types[ty]
336 .name
337 .as_ref()
338 .unwrap()
339 .to_upper_camel_case();
340 if self.uses_two_names(&info) {
341 format!("{name}Param")
342 } else {
343 name
344 }
345 }
346
347 fn result_name(&self, ty: TypeId) -> String {
348 let info = self.info(ty);
349 let name = self.resolve().types[ty]
350 .name
351 .as_ref()
352 .unwrap()
353 .to_upper_camel_case();
354 if self.uses_two_names(&info) {
355 format!("{name}Result")
356 } else {
357 name
358 }
359 }
360
361 fn uses_two_names(&self, info: &TypeInfo) -> bool {
362 info.has_list
363 && info.borrowed
364 && info.owned
365 && matches!(
366 self.ownership(),
367 Ownership::Borrowing {
368 duplicate_if_necessary: true
369 }
370 )
371 }
372
373 fn lifetime_for(&self, info: &TypeInfo, mode: TypeMode) -> Option<&'static str> {
374 if matches!(self.ownership(), Ownership::Owning) {
375 return None;
376 }
377 let lt = match mode {
378 TypeMode::AllBorrowed(s) => s,
379 _ => return None,
380 };
381 if !info.has_list {
383 return None;
384 }
385 if self.uses_two_names(info) || (info.borrowed && !info.owned) {
391 Some(lt)
392 } else {
393 None
394 }
395 }
396
397 fn typedfunc_sig(&self, func: &Function, param_mode: TypeMode) -> String {
398 let mut out = "(".to_string();
399 for (_, ty) in func.params.iter() {
400 out.push_str(&self.ty(ty, param_mode));
401 out.push_str(", ");
402 }
403 out.push_str("), (");
404 if let Some(ty) = func.result {
405 out.push_str(&self.ty(&ty, TypeMode::Owned));
406 out.push_str(", ");
407 }
408 out.push_str(")");
409 out
410 }
411}
412
413pub fn to_rust_ident(name: &str) -> String {
415 match name {
416 "as" => "as_".into(),
419 "break" => "break_".into(),
420 "const" => "const_".into(),
421 "continue" => "continue_".into(),
422 "crate" => "crate_".into(),
423 "else" => "else_".into(),
424 "enum" => "enum_".into(),
425 "extern" => "extern_".into(),
426 "false" => "false_".into(),
427 "fn" => "fn_".into(),
428 "for" => "for_".into(),
429 "if" => "if_".into(),
430 "impl" => "impl_".into(),
431 "in" => "in_".into(),
432 "let" => "let_".into(),
433 "loop" => "loop_".into(),
434 "match" => "match_".into(),
435 "mod" => "mod_".into(),
436 "move" => "move_".into(),
437 "mut" => "mut_".into(),
438 "pub" => "pub_".into(),
439 "ref" => "ref_".into(),
440 "return" => "return_".into(),
441 "self" => "self_".into(),
442 "static" => "static_".into(),
443 "struct" => "struct_".into(),
444 "super" => "super_".into(),
445 "trait" => "trait_".into(),
446 "true" => "true_".into(),
447 "type" => "type_".into(),
448 "unsafe" => "unsafe_".into(),
449 "use" => "use_".into(),
450 "where" => "where_".into(),
451 "while" => "while_".into(),
452 "async" => "async_".into(),
453 "await" => "await_".into(),
454 "dyn" => "dyn_".into(),
455 "abstract" => "abstract_".into(),
456 "become" => "become_".into(),
457 "box" => "box_".into(),
458 "do" => "do_".into(),
459 "final" => "final_".into(),
460 "macro" => "macro_".into(),
461 "override" => "override_".into(),
462 "priv" => "priv_".into(),
463 "typeof" => "typeof_".into(),
464 "unsized" => "unsized_".into(),
465 "virtual" => "virtual_".into(),
466 "yield" => "yield_".into(),
467 "try" => "try_".into(),
468 "gen" => "gen_".into(),
469 s => s.to_snake_case(),
470 }
471}
472
473pub fn to_rust_upper_camel_case(name: &str) -> String {
475 match name {
476 "host" => "Host_".into(),
479 s => s.to_upper_camel_case(),
480 }
481}