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:
Jakub Konka
2019-11-07 15:16:34 +01:00
120 changed files with 14853 additions and 5 deletions

View 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()
}