1 use crate::config::{AsyncConf, ErrorConf, ErrorConfField, TracingConf}; 2 use proc_macro2::{Ident, TokenStream}; 3 use quote::quote; 4 use std::collections::HashMap; 5 use std::rc::Rc; 6 use wasmtime_environ::error::{Error, format_err}; 7 use witx::{Document, Id, InterfaceFunc, Module, NamedType, TypeRef}; 8 9 pub use crate::config::Asyncness; 10 11 pub struct CodegenSettings { 12 pub errors: ErrorTransform, 13 pub async_: AsyncConf, 14 pub wasmtime: bool, 15 /// Disabling this feature makes it possible to remove all of the tracing 16 /// code emitted in the Wiggle-generated code; this can be helpful while 17 /// inspecting the code (e.g., with `cargo expand`). 18 pub tracing: TracingConf, 19 /// Determine whether the context structure will use `&mut self` (true) or 20 /// simply `&self`. 21 pub mutable: bool, 22 } 23 impl CodegenSettings { new( error_conf: &ErrorConf, async_: &AsyncConf, doc: &Document, wasmtime: bool, tracing: &TracingConf, mutable: bool, ) -> Result<Self, Error>24 pub fn new( 25 error_conf: &ErrorConf, 26 async_: &AsyncConf, 27 doc: &Document, 28 wasmtime: bool, 29 tracing: &TracingConf, 30 mutable: bool, 31 ) -> Result<Self, Error> { 32 let errors = ErrorTransform::new(error_conf, doc)?; 33 Ok(Self { 34 errors, 35 async_: async_.clone(), 36 wasmtime, 37 tracing: tracing.clone(), 38 mutable, 39 }) 40 } get_async(&self, module: &Module, func: &InterfaceFunc) -> Asyncness41 pub fn get_async(&self, module: &Module, func: &InterfaceFunc) -> Asyncness { 42 self.async_.get(module.name.as_str(), func.name.as_str()) 43 } 44 } 45 46 pub struct ErrorTransform { 47 m: Vec<ErrorType>, 48 } 49 50 impl ErrorTransform { empty() -> Self51 pub fn empty() -> Self { 52 Self { m: Vec::new() } 53 } new(conf: &ErrorConf, doc: &Document) -> Result<Self, Error>54 pub fn new(conf: &ErrorConf, doc: &Document) -> Result<Self, Error> { 55 let mut richtype_identifiers = HashMap::new(); 56 let m = conf.iter().map(|(ident, field)| 57 match field { 58 ErrorConfField::Trappable(field) => if let Some(abi_type) = doc.typename(&Id::new(ident.to_string())) { 59 Ok(ErrorType::Generated(TrappableErrorType { abi_type, rich_type: field.rich_error.clone() })) 60 } else { 61 Err(format_err!("No witx typename \"{}\" found", ident.to_string())) 62 }, 63 ErrorConfField::User(field) => if let Some(abi_type) = doc.typename(&Id::new(ident.to_string())) { 64 if let Some(ident) = field.rich_error.get_ident() { 65 if let Some(prior_def) = richtype_identifiers.insert(ident.clone(), field.err_loc) 66 { 67 return Err(format_err!( 68 "duplicate rich type identifier of {ident:?} not allowed. prior definition at {prior_def:?}", 69 )); 70 } 71 Ok(ErrorType::User(UserErrorType { 72 abi_type, 73 rich_type: field.rich_error.clone(), 74 method_fragment: ident.to_string() 75 })) 76 } else { 77 return Err(format_err!( 78 "rich error type must be identifier for now - TODO add ability to provide a corresponding identifier: {:?}", 79 field.err_loc 80 )) 81 } 82 } 83 else { Err(format_err!("No witx typename \"{}\" found", ident.to_string())) } 84 } 85 ).collect::<Result<Vec<_>, Error>>()?; 86 Ok(Self { m }) 87 } 88 iter(&self) -> impl Iterator<Item = &ErrorType>89 pub fn iter(&self) -> impl Iterator<Item = &ErrorType> { 90 self.m.iter() 91 } 92 for_abi_error(&self, tref: &TypeRef) -> Option<&ErrorType>93 pub fn for_abi_error(&self, tref: &TypeRef) -> Option<&ErrorType> { 94 match tref { 95 TypeRef::Name(nt) => self.for_name(nt), 96 TypeRef::Value { .. } => None, 97 } 98 } 99 for_name(&self, nt: &NamedType) -> Option<&ErrorType>100 pub fn for_name(&self, nt: &NamedType) -> Option<&ErrorType> { 101 self.m.iter().find(|e| e.abi_type().name == nt.name) 102 } 103 } 104 105 pub enum ErrorType { 106 User(UserErrorType), 107 Generated(TrappableErrorType), 108 } 109 impl ErrorType { abi_type(&self) -> &NamedType110 pub fn abi_type(&self) -> &NamedType { 111 match self { 112 Self::User(u) => &u.abi_type, 113 Self::Generated(r) => &r.abi_type, 114 } 115 } 116 } 117 118 pub struct TrappableErrorType { 119 abi_type: Rc<NamedType>, 120 rich_type: Ident, 121 } 122 123 impl TrappableErrorType { abi_type(&self) -> TypeRef124 pub fn abi_type(&self) -> TypeRef { 125 TypeRef::Name(self.abi_type.clone()) 126 } typename(&self) -> TokenStream127 pub fn typename(&self) -> TokenStream { 128 let richtype = &self.rich_type; 129 quote!(#richtype) 130 } 131 } 132 133 pub struct UserErrorType { 134 abi_type: Rc<NamedType>, 135 rich_type: syn::Path, 136 method_fragment: String, 137 } 138 139 impl UserErrorType { abi_type(&self) -> TypeRef140 pub fn abi_type(&self) -> TypeRef { 141 TypeRef::Name(self.abi_type.clone()) 142 } typename(&self) -> TokenStream143 pub fn typename(&self) -> TokenStream { 144 let t = &self.rich_type; 145 quote!(#t) 146 } method_fragment(&self) -> &str147 pub fn method_fragment(&self) -> &str { 148 &self.method_fragment 149 } 150 } 151