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:
@@ -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())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user