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 106 107 108 109
extern crate proc_macro; use proc_macro::TokenStream; use quote::quote; use syn::parse_macro_input; /// This macro expands to a set of `pub` Rust modules: /// /// * The `types` module contains definitions for each `typename` declared in /// the witx document. Type names are translated to the Rust-idiomatic /// CamelCase. /// /// * For each `module` defined in the witx document, a Rust module is defined /// containing definitions for that module. Module names are teanslated to the /// Rust-idiomatic snake\_case. /// /// * For each `@interface func` defined in a witx module, an abi-level /// function is generated which takes ABI-level arguments, along with a /// "context" struct (whose type is given by the `ctx` field in the /// macro invocation) and a `GuestMemory` implementation. /// /// * A public "module trait" is defined (called the module name, in /// SnakeCase) which has a `&self` method for each function in the /// module. These methods takes idiomatic Rust types for each argument /// and return `Result<($return_types),$error_type>` /// /// Arguments are provided using Rust struct value syntax. /// /// * `witx` takes a list of string literal paths. Paths are relative to the /// CARGO_MANIFEST_DIR of the crate where the macro is invoked. /// * `ctx` takes a type name. This type must implement all of the module /// traits /// /// ## Example /// /// ``` /// use wiggle::{GuestPtr, GuestErrorType}; /// /// /// The test witx file `arrays.witx` lives in the test directory. For a /// /// full-fledged example with runtime tests, see `tests/arrays.rs` and /// /// the rest of the files in that directory. /// wiggle::from_witx!({ /// witx: ["../tests/arrays.witx"], /// ctx: YourCtxType, /// }); /// /// /// The `ctx` type for this wiggle invocation. /// pub struct YourCtxType {} /// /// /// `arrays.witx` contains one module called `arrays`. So, we must /// /// implement this one method trait for our ctx type: /// impl arrays::Arrays for YourCtxType { /// /// The arrays module has two methods, shown here. /// /// Note that the `GuestPtr` type comes from `wiggle`, /// /// whereas the witx-defined types like `Excuse` and `Errno` come /// /// from the `pub mod types` emitted by the `wiggle::from_witx!` /// /// invocation above. /// fn reduce_excuses(&self, _a: &GuestPtr<[GuestPtr<types::Excuse>]>) /// -> Result<types::Excuse, types::Errno> { /// unimplemented!() /// } /// fn populate_excuses(&self, _a: &GuestPtr<[GuestPtr<types::Excuse>]>) /// -> Result<(), types::Errno> { /// unimplemented!() /// } /// } /// /// /// For all types used in the `Error` position of a `Result` in the module /// /// traits, you must implement `GuestErrorType` which tells wiggle-generated /// /// code what value to return when the method returns Ok(...). /// impl GuestErrorType for types::Errno { /// fn success() -> Self { /// unimplemented!() /// } /// } /// /// /// The `types::GuestErrorConversion` trait is also generated with a method for /// /// each type used in the `Error` position. This trait allows wiggle-generated /// /// code to convert a `wiggle::GuestError` into the right error type. The trait /// /// must be implemented for the user's `ctx` type. /// /// impl types::GuestErrorConversion for YourCtxType { /// fn into_errno(&self, _e: wiggle::GuestError) -> types::Errno { /// unimplemented!() /// } /// } /// /// # fn main() { println!("this fools doc tests into compiling the above outside a function body") /// # } /// ``` #[proc_macro] pub fn from_witx(args: TokenStream) -> TokenStream { let mut config = parse_macro_input!(args as wiggle_generate::Config); config.witx.make_paths_relative_to( std::env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR env var"), ); let doc = witx::load(&config.witx.paths).expect("loading witx"); let names = wiggle_generate::Names::new(&config.ctx.name, quote!(wiggle)); let code = wiggle_generate::generate(&doc, &names); let metadata = if cfg!(feature = "wiggle_metadata") { wiggle_generate::generate_metadata(&doc, &names) } else { quote!() }; TokenStream::from(quote! { #code #metadata }) }