Merge wasi-common into wasmtime
This commit merges [CraneStation/wasi-common] repo as a subdir of this repo while preserving **all** of git history. There is an initiative to pull `wasi-common` into [CraneStation/wasmtime], and [CraneStation/wasmtime] becoming a monorepo. This came about for several reasons with a common theme of convenience, namely, having a monorepo: 1. cleans up the problem of dependencies (as we have seen first hand with dependabot enabled, it can cause some grief) 2. completely removes the problem of syncing the closely dependent repos (e.g., updating `wasi-common` with say a bugfix generally implies creating a "sync" commit for pulling in the changes into the "parent" repo, in this case, `wasmtime`) 3. mainly for the two reasons above, makes publishing to crates.io easier 4. hopefully streamlines the process of getting the community involved in contributing to `wasi-common` as now everything is one place [CraneStation/wasi-common]: https://github.com/CraneStation/wasi-common [CraneStation/wasmtime]: https://github.com/CraneStation/wasmtime
This commit is contained in:
107
wasi-common/wasi-common-cbindgen/src/lib.rs
Normal file
107
wasi-common/wasi-common-cbindgen/src/lib.rs
Normal file
@@ -0,0 +1,107 @@
|
||||
extern crate proc_macro;
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::{FnArg, Pat, PatType, Type, TypeReference, TypeSlice};
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn wasi_common_cbindgen(attr: TokenStream, function: TokenStream) -> TokenStream {
|
||||
assert!(attr.is_empty());
|
||||
|
||||
let function = syn::parse_macro_input!(function as syn::ItemFn);
|
||||
|
||||
// capture visibility
|
||||
let vis = &function.vis;
|
||||
|
||||
// generate C fn name prefixed with __wasi_
|
||||
let fn_ident = &function.sig.ident;
|
||||
let concatenated = format!("wasi_common_{}", fn_ident);
|
||||
let c_fn_ident = syn::Ident::new(&concatenated, fn_ident.span());
|
||||
|
||||
// capture input args
|
||||
let mut arg_ident = Vec::new();
|
||||
let mut arg_type = Vec::new();
|
||||
let mut call_arg_ident = Vec::new();
|
||||
for input in &function.sig.inputs {
|
||||
match input {
|
||||
FnArg::Typed(PatType {
|
||||
attrs,
|
||||
pat,
|
||||
colon_token: _,
|
||||
ty,
|
||||
}) => {
|
||||
// parse arg identifier
|
||||
let ident = if let Pat::Ident(ident) = &**pat {
|
||||
&ident.ident
|
||||
} else {
|
||||
panic!("expected function input to be an identifier")
|
||||
};
|
||||
if !attrs.is_empty() {
|
||||
panic!("unsupported attributes on function arg");
|
||||
}
|
||||
arg_ident.push(quote!(#ident));
|
||||
// parse arg type
|
||||
if let Type::Reference(ty @ TypeReference { .. }) = &**ty {
|
||||
// if we're here, then we found a &-ref
|
||||
// so substitute it for *mut since we're exporting to C
|
||||
let elem = &*ty.elem;
|
||||
if let Type::Slice(elem @ TypeSlice { .. }) = &elem {
|
||||
// slice: &[type] or &mut [type]
|
||||
// in C it requires a signature *mut type
|
||||
let elem = &elem.elem;
|
||||
arg_type.push(quote!(*mut #elem));
|
||||
// since it's a slice, we'll need to do more work here
|
||||
// simple dereferencing is not enough
|
||||
// firstly, we need to add a len arg to C fn
|
||||
// secondly, we need to invoke std::slice::from_raw_parts_mut(..)
|
||||
let concatenated = format!("{}_len", ident);
|
||||
let len_ident = syn::Ident::new(&concatenated, ident.span());
|
||||
call_arg_ident.push(quote! {
|
||||
std::slice::from_raw_parts_mut(#ident, #len_ident)
|
||||
});
|
||||
arg_ident.push(quote!(#len_ident));
|
||||
arg_type.push(quote!(usize));
|
||||
} else {
|
||||
// & or &mut type; substitute with *const or *mut type.
|
||||
// Also, we need to properly dereference the substituted raw
|
||||
// pointer if we are to properly call the hostcall fn.
|
||||
if ty.mutability.is_none() {
|
||||
arg_type.push(quote!(*const #elem));
|
||||
call_arg_ident.push(quote!(&*#ident));
|
||||
} else {
|
||||
arg_type.push(quote!(*mut #elem));
|
||||
call_arg_ident.push(quote!(&mut *#ident));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
arg_type.push(quote!(#ty));
|
||||
// non-&-ref type, so preserve whatever the arg was
|
||||
call_arg_ident.push(quote!(#ident));
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
unimplemented!("unrecognized function input pattern");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// capture output arg
|
||||
let output = &function.sig.output;
|
||||
|
||||
let result = quote! {
|
||||
#function
|
||||
|
||||
#[no_mangle]
|
||||
#vis unsafe extern "C" fn #c_fn_ident(
|
||||
#(
|
||||
#arg_ident: #arg_type,
|
||||
)*
|
||||
) #output {
|
||||
#fn_ident(#(
|
||||
#call_arg_ident,
|
||||
)*)
|
||||
}
|
||||
};
|
||||
|
||||
result.into()
|
||||
}
|
||||
Reference in New Issue
Block a user