wiggle_generate/
codegen_settings.rs1use crate::config::{AsyncConf, ErrorConf, ErrorConfField, TracingConf};
2use anyhow::{anyhow, Error};
3use proc_macro2::{Ident, TokenStream};
4use quote::quote;
5use std::collections::HashMap;
6use std::rc::Rc;
7use witx::{Document, Id, InterfaceFunc, Module, NamedType, TypeRef};
8
9pub use crate::config::Asyncness;
10
11pub struct CodegenSettings {
12 pub errors: ErrorTransform,
13 pub async_: AsyncConf,
14 pub wasmtime: bool,
15 pub tracing: TracingConf,
19 pub mutable: bool,
22}
23impl CodegenSettings {
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 }
41 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
46pub struct ErrorTransform {
47 m: Vec<ErrorType>,
48}
49
50impl ErrorTransform {
51 pub fn empty() -> Self {
52 Self { m: Vec::new() }
53 }
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(anyhow!("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(anyhow!(
68 "duplicate rich type identifier of {:?} not allowed. prior definition at {:?}",
69 ident, prior_def
70 ));
71 }
72 Ok(ErrorType::User(UserErrorType {
73 abi_type,
74 rich_type: field.rich_error.clone(),
75 method_fragment: ident.to_string()
76 }))
77 } else {
78 return Err(anyhow!(
79 "rich error type must be identifier for now - TODO add ability to provide a corresponding identifier: {:?}",
80 field.err_loc
81 ))
82 }
83 }
84 else { Err(anyhow!("No witx typename \"{}\" found", ident.to_string())) }
85 }
86 ).collect::<Result<Vec<_>, Error>>()?;
87 Ok(Self { m })
88 }
89
90 pub fn iter(&self) -> impl Iterator<Item = &ErrorType> {
91 self.m.iter()
92 }
93
94 pub fn for_abi_error(&self, tref: &TypeRef) -> Option<&ErrorType> {
95 match tref {
96 TypeRef::Name(nt) => self.for_name(nt),
97 TypeRef::Value { .. } => None,
98 }
99 }
100
101 pub fn for_name(&self, nt: &NamedType) -> Option<&ErrorType> {
102 self.m.iter().find(|e| e.abi_type().name == nt.name)
103 }
104}
105
106pub enum ErrorType {
107 User(UserErrorType),
108 Generated(TrappableErrorType),
109}
110impl ErrorType {
111 pub fn abi_type(&self) -> &NamedType {
112 match self {
113 Self::User(u) => &u.abi_type,
114 Self::Generated(r) => &r.abi_type,
115 }
116 }
117}
118
119pub struct TrappableErrorType {
120 abi_type: Rc<NamedType>,
121 rich_type: Ident,
122}
123
124impl TrappableErrorType {
125 pub fn abi_type(&self) -> TypeRef {
126 TypeRef::Name(self.abi_type.clone())
127 }
128 pub fn typename(&self) -> TokenStream {
129 let richtype = &self.rich_type;
130 quote!(#richtype)
131 }
132}
133
134pub struct UserErrorType {
135 abi_type: Rc<NamedType>,
136 rich_type: syn::Path,
137 method_fragment: String,
138}
139
140impl UserErrorType {
141 pub fn abi_type(&self) -> TypeRef {
142 TypeRef::Name(self.abi_type.clone())
143 }
144 pub fn typename(&self) -> TokenStream {
145 let t = &self.rich_type;
146 quote!(#t)
147 }
148 pub fn method_fragment(&self) -> &str {
149 &self.method_fragment
150 }
151}