1mod codegen_settings;
2pub mod config;
3mod funcs;
4mod lifetimes;
5mod module_trait;
6pub mod names;
7mod types;
8pub mod wasmtime;
9
10use heck::ToShoutySnakeCase;
11use lifetimes::anon_lifetime;
12use proc_macro2::{Literal, TokenStream};
13use quote::quote;
14
15pub use codegen_settings::{CodegenSettings, ErrorType, UserErrorType};
16pub use config::{Config, WasmtimeConfig};
17pub use funcs::define_func;
18pub use module_trait::define_module_trait;
19pub use types::define_datatype;
20
21pub fn generate(doc: &witx::Document, settings: &CodegenSettings) -> TokenStream {
22 let types = doc
23 .typenames()
24 .map(|t| define_datatype(&t, settings.errors.for_name(&t)));
25
26 let constants = doc.constants().map(|c| {
27 let name = quote::format_ident!(
28 "{}_{}",
29 c.ty.as_str().to_shouty_snake_case(),
30 c.name.as_str().to_shouty_snake_case()
31 );
32 let ty = names::type_(&c.ty);
33 let value = Literal::u64_unsuffixed(c.value);
34 quote! {
35 pub const #name: #ty = #value;
36 }
37 });
38
39 let user_error_methods = settings.errors.iter().filter_map(|errtype| match errtype {
40 ErrorType::User(errtype) => {
41 let abi_typename = names::type_ref(&errtype.abi_type(), anon_lifetime());
42 let user_typename = errtype.typename();
43 let methodname = names::user_error_conversion_method(&errtype);
44 Some(quote! {
45 fn #methodname(&mut self, e: super::#user_typename)
46 -> wiggle::anyhow::Result<#abi_typename>;
47 })
48 }
49 ErrorType::Generated(_) => None,
50 });
51 let user_error_conversion = quote! {
52 pub trait UserErrorConversion {
53 #(#user_error_methods)*
54 }
55 };
56 let modules = doc.modules().map(|module| {
57 let modname = names::module(&module.name);
58 let fs = module.funcs().map(|f| define_func(&module, &f, &settings));
59 let modtrait = define_module_trait(&module, &settings);
60 let wasmtime = if settings.wasmtime {
61 crate::wasmtime::link_module(&module, None, &settings)
62 } else {
63 quote! {}
64 };
65 quote!(
66 pub mod #modname {
67 use super::types::*;
68 pub use super::types::UserErrorConversion;
69 #(#fs)*
70
71 #modtrait
72
73 #wasmtime
74 }
75 )
76 });
77
78 quote!(
79 pub mod types {
80 use std::convert::TryFrom;
81
82 #(#types)*
83 #(#constants)*
84 #user_error_conversion
85 }
86 #(#modules)*
87 )
88}
89
90pub fn generate_metadata(doc: &witx::Document) -> TokenStream {
91 let doc_text = &format!("{doc}");
92 quote! {
93 pub mod metadata {
94 pub const DOC_TEXT: &str = #doc_text;
95 pub fn document() -> wiggle::witx::Document {
96 wiggle::witx::parse(DOC_TEXT).unwrap()
97 }
98 }
99 }
100}