Implement RFC 11: Redesigning Wasmtime's APIs (#2897)

Implement Wasmtime's new API as designed by RFC 11. This is quite a large commit which has had lots of discussion externally, so for more information it's best to read the RFC thread and the PR thread.
This commit is contained in:
Alex Crichton
2021-06-03 09:10:53 -05:00
committed by GitHub
parent a5a28b1c5b
commit 7a1b7cdf92
233 changed files with 13349 additions and 11997 deletions

View File

@@ -14,6 +14,16 @@ pub struct Config {
pub witx: WitxConf,
pub errors: ErrorConf,
pub async_: AsyncConf,
pub wasmtime: bool,
}
mod kw {
syn::custom_keyword!(witx);
syn::custom_keyword!(witx_literal);
syn::custom_keyword!(block_on);
syn::custom_keyword!(errors);
syn::custom_keyword!(target);
syn::custom_keyword!(wasmtime);
}
#[derive(Debug, Clone)]
@@ -21,12 +31,7 @@ pub enum ConfigField {
Witx(WitxConf),
Error(ErrorConf),
Async(AsyncConf),
}
mod kw {
syn::custom_keyword!(witx);
syn::custom_keyword!(witx_literal);
syn::custom_keyword!(errors);
Wasmtime(bool),
}
impl Parse for ConfigField {
@@ -48,8 +53,20 @@ impl Parse for ConfigField {
input.parse::<Token![async]>()?;
input.parse::<Token![:]>()?;
Ok(ConfigField::Async(AsyncConf {
blocking: false,
functions: input.parse()?,
}))
} else if lookahead.peek(kw::block_on) {
input.parse::<kw::block_on>()?;
input.parse::<Token![:]>()?;
Ok(ConfigField::Async(AsyncConf {
blocking: true,
functions: input.parse()?,
}))
} else if lookahead.peek(kw::wasmtime) {
input.parse::<kw::wasmtime>()?;
input.parse::<Token![:]>()?;
Ok(ConfigField::Wasmtime(input.parse::<syn::LitBool>()?.value))
} else {
Err(lookahead.error())
}
@@ -61,6 +78,7 @@ impl Config {
let mut witx = None;
let mut errors = None;
let mut async_ = None;
let mut wasmtime = None;
for f in fields {
match f {
ConfigField::Witx(c) => {
@@ -81,6 +99,12 @@ impl Config {
}
async_ = Some(c);
}
ConfigField::Wasmtime(c) => {
if wasmtime.is_some() {
return Err(Error::new(err_loc, "duplicate `wasmtime` field"));
}
wasmtime = Some(c);
}
}
}
Ok(Config {
@@ -89,6 +113,7 @@ impl Config {
.ok_or_else(|| Error::new(err_loc, "`witx` field required"))?,
errors: errors.take().unwrap_or_default(),
async_: async_.take().unwrap_or_default(),
wasmtime: wasmtime.unwrap_or(true),
})
}
@@ -284,9 +309,41 @@ impl Parse for ErrorConfField {
#[derive(Clone, Default, Debug)]
/// Modules and funcs that have async signatures
pub struct AsyncConf {
blocking: bool,
functions: AsyncFunctions,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Asyncness {
/// Wiggle function is synchronous, wasmtime Func is synchronous
Sync,
/// Wiggle function is asynchronous, but wasmtime Func is synchronous
Blocking,
/// Wiggle function and wasmtime Func are asynchronous.
Async,
}
impl Asyncness {
pub fn is_async(&self) -> bool {
match self {
Self::Async => true,
_ => false,
}
}
pub fn is_blocking(&self) -> bool {
match self {
Self::Blocking => true,
_ => false,
}
}
pub fn is_sync(&self) -> bool {
match self {
Self::Sync => true,
_ => false,
}
}
}
#[derive(Clone, Debug)]
pub enum AsyncFunctions {
Some(HashMap<String, Vec<String>>),
@@ -299,15 +356,36 @@ impl Default for AsyncFunctions {
}
impl AsyncConf {
pub fn is_async(&self, module: &str, function: &str) -> bool {
pub fn get(&self, module: &str, function: &str) -> Asyncness {
let a = if self.blocking {
Asyncness::Blocking
} else {
Asyncness::Async
};
match &self.functions {
AsyncFunctions::Some(fs) => fs
.get(module)
.and_then(|fs| fs.iter().find(|f| *f == function))
.is_some(),
AsyncFunctions::All => true,
AsyncFunctions::Some(fs) => {
if fs
.get(module)
.and_then(|fs| fs.iter().find(|f| *f == function))
.is_some()
{
a
} else {
Asyncness::Sync
}
}
AsyncFunctions::All => a,
}
}
pub fn contains_async(&self, module: &witx::Module) -> bool {
for f in module.funcs() {
if self.get(module.name.as_str(), f.name.as_str()).is_async() {
return true;
}
}
false
}
}
impl Parse for AsyncFunctions {
@@ -378,3 +456,97 @@ impl Parse for AsyncConfField {
}
}
}
#[derive(Clone)]
pub struct WasmtimeConfig {
pub c: Config,
pub target: syn::Path,
}
#[derive(Clone)]
pub enum WasmtimeConfigField {
Core(ConfigField),
Target(syn::Path),
}
impl WasmtimeConfig {
pub fn build(fields: impl Iterator<Item = WasmtimeConfigField>, err_loc: Span) -> Result<Self> {
let mut target = None;
let mut cs = Vec::new();
for f in fields {
match f {
WasmtimeConfigField::Target(c) => {
if target.is_some() {
return Err(Error::new(err_loc, "duplicate `target` field"));
}
target = Some(c);
}
WasmtimeConfigField::Core(c) => cs.push(c),
}
}
let c = Config::build(cs.into_iter(), err_loc)?;
Ok(WasmtimeConfig {
c,
target: target
.take()
.ok_or_else(|| Error::new(err_loc, "`target` field required"))?,
})
}
}
impl Parse for WasmtimeConfig {
fn parse(input: ParseStream) -> Result<Self> {
let contents;
let _lbrace = braced!(contents in input);
let fields: Punctuated<WasmtimeConfigField, Token![,]> =
contents.parse_terminated(WasmtimeConfigField::parse)?;
Ok(WasmtimeConfig::build(fields.into_iter(), input.span())?)
}
}
impl Parse for WasmtimeConfigField {
fn parse(input: ParseStream) -> Result<Self> {
let lookahead = input.lookahead1();
if lookahead.peek(kw::target) {
input.parse::<kw::target>()?;
input.parse::<Token![:]>()?;
Ok(WasmtimeConfigField::Target(input.parse()?))
// The remainder of this function is the ConfigField impl, wrapped in
// WasmtimeConfigField::Core. This is required to get the correct lookahead error.
} else if lookahead.peek(kw::witx) {
input.parse::<kw::witx>()?;
input.parse::<Token![:]>()?;
Ok(WasmtimeConfigField::Core(ConfigField::Witx(
WitxConf::Paths(input.parse()?),
)))
} else if lookahead.peek(kw::witx_literal) {
input.parse::<kw::witx_literal>()?;
input.parse::<Token![:]>()?;
Ok(WasmtimeConfigField::Core(ConfigField::Witx(
WitxConf::Literal(input.parse()?),
)))
} else if lookahead.peek(kw::errors) {
input.parse::<kw::errors>()?;
input.parse::<Token![:]>()?;
Ok(WasmtimeConfigField::Core(ConfigField::Error(
input.parse()?,
)))
} else if lookahead.peek(Token![async]) {
input.parse::<Token![async]>()?;
input.parse::<Token![:]>()?;
Ok(WasmtimeConfigField::Core(ConfigField::Async(AsyncConf {
blocking: false,
functions: input.parse()?,
})))
} else if lookahead.peek(kw::block_on) {
input.parse::<kw::block_on>()?;
input.parse::<Token![:]>()?;
Ok(WasmtimeConfigField::Core(ConfigField::Async(AsyncConf {
blocking: true,
functions: input.parse()?,
})))
} else {
Err(lookahead.error())
}
}
}