1 use crate::config::{AsyncConf, ErrorConf}; 2 use anyhow::{anyhow, Error}; 3 use proc_macro2::TokenStream; 4 use quote::quote; 5 use std::collections::HashMap; 6 use std::rc::Rc; 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 } 16 impl CodegenSettings { 17 pub fn new( 18 error_conf: &ErrorConf, 19 async_: &AsyncConf, 20 doc: &Document, 21 wasmtime: bool, 22 ) -> Result<Self, Error> { 23 let errors = ErrorTransform::new(error_conf, doc)?; 24 Ok(Self { 25 errors, 26 async_: async_.clone(), 27 wasmtime, 28 }) 29 } 30 pub fn get_async(&self, module: &Module, func: &InterfaceFunc) -> Asyncness { 31 self.async_.get(module.name.as_str(), func.name.as_str()) 32 } 33 } 34 35 pub struct ErrorTransform { 36 m: Vec<UserErrorType>, 37 } 38 39 impl ErrorTransform { 40 pub fn empty() -> Self { 41 Self { m: Vec::new() } 42 } 43 pub fn new(conf: &ErrorConf, doc: &Document) -> Result<Self, Error> { 44 let mut richtype_identifiers = HashMap::new(); 45 let m = conf.iter().map(|(ident, field)| 46 if let Some(abi_type) = doc.typename(&Id::new(ident.to_string())) { 47 if let Some(ident) = field.rich_error.get_ident() { 48 if let Some(prior_def) = richtype_identifiers.insert(ident.clone(), field.err_loc.clone()) 49 { 50 return Err(anyhow!( 51 "duplicate rich type identifier of {:?} not allowed. prior definition at {:?}", 52 ident, prior_def 53 )); 54 } 55 Ok(UserErrorType { 56 abi_type, 57 rich_type: field.rich_error.clone(), 58 method_fragment: ident.to_string() 59 }) 60 } else { 61 return Err(anyhow!( 62 "rich error type must be identifier for now - TODO add ability to provide a corresponding identifier: {:?}", 63 field.err_loc 64 )) 65 } 66 } 67 else { Err(anyhow!("No witx typename \"{}\" found", ident.to_string())) } 68 ).collect::<Result<Vec<_>, Error>>()?; 69 Ok(Self { m }) 70 } 71 72 pub fn iter(&self) -> impl Iterator<Item = &UserErrorType> { 73 self.m.iter() 74 } 75 76 pub fn for_abi_error(&self, tref: &TypeRef) -> Option<&UserErrorType> { 77 match tref { 78 TypeRef::Name(nt) => self.for_name(nt), 79 TypeRef::Value { .. } => None, 80 } 81 } 82 83 pub fn for_name(&self, nt: &NamedType) -> Option<&UserErrorType> { 84 self.m.iter().find(|u| u.abi_type.name == nt.name) 85 } 86 } 87 88 pub struct UserErrorType { 89 abi_type: Rc<NamedType>, 90 rich_type: syn::Path, 91 method_fragment: String, 92 } 93 94 impl UserErrorType { 95 pub fn abi_type(&self) -> TypeRef { 96 TypeRef::Name(self.abi_type.clone()) 97 } 98 pub fn typename(&self) -> TokenStream { 99 let t = &self.rich_type; 100 quote!(#t) 101 } 102 pub fn method_fragment(&self) -> &str { 103 &self.method_fragment 104 } 105 } 106