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