Path: blob/main/crates/wiggle/generate/src/codegen_settings.rs
3054 views
use crate::config::{AsyncConf, ErrorConf, ErrorConfField, TracingConf};1use proc_macro2::{Ident, TokenStream};2use quote::quote;3use std::collections::HashMap;4use std::rc::Rc;5use wasmtime_environ::error::{Error, format_err};6use witx::{Document, Id, InterfaceFunc, Module, NamedType, TypeRef};78pub use crate::config::Asyncness;910pub struct CodegenSettings {11pub errors: ErrorTransform,12pub async_: AsyncConf,13pub wasmtime: bool,14/// Disabling this feature makes it possible to remove all of the tracing15/// code emitted in the Wiggle-generated code; this can be helpful while16/// inspecting the code (e.g., with `cargo expand`).17pub tracing: TracingConf,18/// Determine whether the context structure will use `&mut self` (true) or19/// simply `&self`.20pub mutable: bool,21}22impl CodegenSettings {23pub fn new(24error_conf: &ErrorConf,25async_: &AsyncConf,26doc: &Document,27wasmtime: bool,28tracing: &TracingConf,29mutable: bool,30) -> Result<Self, Error> {31let errors = ErrorTransform::new(error_conf, doc)?;32Ok(Self {33errors,34async_: async_.clone(),35wasmtime,36tracing: tracing.clone(),37mutable,38})39}40pub fn get_async(&self, module: &Module, func: &InterfaceFunc) -> Asyncness {41self.async_.get(module.name.as_str(), func.name.as_str())42}43}4445pub struct ErrorTransform {46m: Vec<ErrorType>,47}4849impl ErrorTransform {50pub fn empty() -> Self {51Self { m: Vec::new() }52}53pub fn new(conf: &ErrorConf, doc: &Document) -> Result<Self, Error> {54let mut richtype_identifiers = HashMap::new();55let m = conf.iter().map(|(ident, field)|56match field {57ErrorConfField::Trappable(field) => if let Some(abi_type) = doc.typename(&Id::new(ident.to_string())) {58Ok(ErrorType::Generated(TrappableErrorType { abi_type, rich_type: field.rich_error.clone() }))59} else {60Err(format_err!("No witx typename \"{}\" found", ident.to_string()))61},62ErrorConfField::User(field) => if let Some(abi_type) = doc.typename(&Id::new(ident.to_string())) {63if let Some(ident) = field.rich_error.get_ident() {64if let Some(prior_def) = richtype_identifiers.insert(ident.clone(), field.err_loc)65{66return Err(format_err!(67"duplicate rich type identifier of {ident:?} not allowed. prior definition at {prior_def:?}",68));69}70Ok(ErrorType::User(UserErrorType {71abi_type,72rich_type: field.rich_error.clone(),73method_fragment: ident.to_string()74}))75} else {76return Err(format_err!(77"rich error type must be identifier for now - TODO add ability to provide a corresponding identifier: {:?}",78field.err_loc79))80}81}82else { Err(format_err!("No witx typename \"{}\" found", ident.to_string())) }83}84).collect::<Result<Vec<_>, Error>>()?;85Ok(Self { m })86}8788pub fn iter(&self) -> impl Iterator<Item = &ErrorType> {89self.m.iter()90}9192pub fn for_abi_error(&self, tref: &TypeRef) -> Option<&ErrorType> {93match tref {94TypeRef::Name(nt) => self.for_name(nt),95TypeRef::Value { .. } => None,96}97}9899pub fn for_name(&self, nt: &NamedType) -> Option<&ErrorType> {100self.m.iter().find(|e| e.abi_type().name == nt.name)101}102}103104pub enum ErrorType {105User(UserErrorType),106Generated(TrappableErrorType),107}108impl ErrorType {109pub fn abi_type(&self) -> &NamedType {110match self {111Self::User(u) => &u.abi_type,112Self::Generated(r) => &r.abi_type,113}114}115}116117pub struct TrappableErrorType {118abi_type: Rc<NamedType>,119rich_type: Ident,120}121122impl TrappableErrorType {123pub fn abi_type(&self) -> TypeRef {124TypeRef::Name(self.abi_type.clone())125}126pub fn typename(&self) -> TokenStream {127let richtype = &self.rich_type;128quote!(#richtype)129}130}131132pub struct UserErrorType {133abi_type: Rc<NamedType>,134rich_type: syn::Path,135method_fragment: String,136}137138impl UserErrorType {139pub fn abi_type(&self) -> TypeRef {140TypeRef::Name(self.abi_type.clone())141}142pub fn typename(&self) -> TokenStream {143let t = &self.rich_type;144quote!(#t)145}146pub fn method_fragment(&self) -> &str {147&self.method_fragment148}149}150151152