1 use proc_macro2::TokenStream;
2 use quote::quote;
3 
4 use crate::codegen_settings::{CodegenSettings, ErrorType};
5 use crate::names;
6 use witx::Module;
7 
passed_by_reference(ty: &witx::Type) -> bool8 pub fn passed_by_reference(ty: &witx::Type) -> bool {
9     match ty {
10         witx::Type::Record(r) => r.bitflags_repr().is_none(),
11         witx::Type::Variant(v) => !v.is_enum(),
12         _ => false,
13     }
14 }
15 
define_module_trait(m: &Module, settings: &CodegenSettings) -> TokenStream16 pub fn define_module_trait(m: &Module, settings: &CodegenSettings) -> TokenStream {
17     let traitname = names::trait_name(&m.name);
18     let traitmethods = m.funcs().map(|f| {
19         let funcname = names::func(&f.name);
20         let args = f.params.iter().map(|arg| {
21             let arg_name = names::func_param(&arg.name);
22             let arg_typename = names::type_ref(&arg.tref, quote!());
23             let arg_type = if passed_by_reference(&*arg.tref.type_()) {
24                 quote!(&#arg_typename)
25             } else {
26                 quote!(#arg_typename)
27             };
28             quote!(#arg_name: #arg_type)
29         });
30 
31         let mut result = match f.results.len() {
32             0 if f.noreturn => quote!(wiggle::error::Error),
33             0 => quote!(()),
34             1 => {
35                 let (ok, err) = match &**f.results[0].tref.type_() {
36                     witx::Type::Variant(v) => match v.as_expected() {
37                         Some(p) => p,
38                         None => unimplemented!("anonymous variant ref {:?}", v),
39                     },
40                     _ => unimplemented!(),
41                 };
42 
43                 let ok = match ok {
44                     Some(ty) => names::type_ref(ty, quote!()),
45                     None => quote!(()),
46                 };
47                 let err = match err {
48                     Some(ty) => match settings.errors.for_abi_error(ty) {
49                         Some(ErrorType::User(custom)) => {
50                             let tn = custom.typename();
51                             quote!(super::#tn)
52                         }
53                         Some(ErrorType::Generated(g)) => g.typename(),
54                         None => names::type_ref(ty, quote!()),
55                     },
56                     None => quote!(()),
57                 };
58                 quote!(Result<#ok, #err>)
59             }
60             _ => unimplemented!(),
61         };
62 
63         if !settings.get_async(&m, &f).is_sync() {
64             result = quote!(impl std::future::Future<Output = #result> + Send);
65         }
66 
67         let self_ = if settings.mutable {
68             quote!(&mut self)
69         } else {
70             quote!(&self)
71         };
72         quote!(
73             fn #funcname(
74                 #self_,
75                 mem: &mut wiggle::GuestMemory<'_>,
76                 #(#args),*
77             ) -> #result;
78         )
79     });
80 
81     quote! {
82         pub trait #traitname {
83             #(#traitmethods)*
84 
85             /// Indicates, if this implementation supports it, that the
86             /// specified amount of fuel should be the maximal spent for the
87             /// upcoming function call.
88             fn set_hostcall_fuel(&mut self, fuel: usize) {
89                 let _ = fuel;
90             }
91         }
92     }
93 }
94