Skip to content

Commit 8ff06a7

Browse files
committed
implement "part 1" of WIT Templates
Per WebAssembly/component-model#172, this implements "part 1" of WIT templates, allowing WIT files to define interfaces which contain a single wildcard function, which worlds may import or export. I've taken a "minimalist" approach to this, such that the host binding generator just skips wildcards entirely, leaving it to the host to use dynamic APIs to reflect on the component and do the necessary func_wrap (for imports) and typed_func (for exports) calls directly. This adds two new functions to the public API: - `Component::names`: provides an iterator over the names of the functions imported by the specified instance. - `ExportInstance::funcs`: provides an iterator over the names of the functions exported by this instance. In both cases, I'm open to alternative API designs for getting that information. Note that I've added a temporary dependency override to Cargo.toml, pointing to our fork of wasm-tools, which includes the necessary wit-parser changes. We're still iterating on that and will PR those changes separately. We also have a fork of wit-bindgen with a new "wildcards" test to verify everything works end-to-end: bytecodealliance/wit-bindgen@main...dicej:wit-templates. I'll PR that last once everything else is stable. Signed-off-by: Joel Dice <[email protected]> generate code for wildcards in `bindgen!` This improves upon the raw `func_wrap` and `typed_func` APIs by providing static type checking. Signed-off-by: Joel Dice <[email protected]> address review feedback - Add TODO comment to `Component::function_import_names` (renamed from `names`) - Add `Component::function_export_names` for symmetry (since an embedder may want both sets of names) - Add a couple of codegen tests for the bindgen macro - Use `Func` instead of `TypedFunc` for `__wildcard_matches` to avoid lifetime issues - Update `wit-parser` and use the new `Interface::wildcard` field where applicable - Add `name: &str` parameter to `WildcardMatch::call` trait function Signed-off-by: Joel Dice <[email protected]>
1 parent 2fde253 commit 8ff06a7

File tree

9 files changed

+535
-42
lines changed

9 files changed

+535
-42
lines changed

Cargo.lock

+1-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+3
Original file line numberDiff line numberDiff line change
@@ -261,3 +261,6 @@ harness = false
261261
[[bench]]
262262
name = "wasi"
263263
harness = false
264+
265+
[patch.crates-io]
266+
wit-parser = { git = "https://github.com/dicej/wasm-tools", branch = "wit-templates" }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
default world wildcards-mixed {
2+
import imports: interface {
3+
*: func(s: string, v: u32, l: list<u8>) -> tuple<string, u32, list<u8>>
4+
foo: func(s: string, v: u32, l: list<u8>) -> tuple<string, u32, list<u8>>
5+
bar: func(v: u32) -> u32
6+
}
7+
export exports: interface {
8+
*: func(s: string, v: u32, l: list<u8>) -> tuple<string, u32, list<u8>>
9+
foo: func(s: string, v: u32, l: list<u8>) -> tuple<string, u32, list<u8>>
10+
bar: func(v: u32) -> u32
11+
}
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
default world wildcards {
2+
import imports: interface {
3+
*: func(s: string, v: u32, l: list<u8>) -> tuple<string, u32, list<u8>>
4+
}
5+
export exports: interface {
6+
*: func(s: string, v: u32, l: list<u8>) -> tuple<string, u32, list<u8>>
7+
}
8+
}

crates/wasmtime/src/component/component.rs

+60-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ use std::path::Path;
1010
use std::ptr::NonNull;
1111
use std::sync::Arc;
1212
use wasmtime_environ::component::{
13-
ComponentTypes, GlobalInitializer, LoweredIndex, RuntimeAlwaysTrapIndex,
14-
RuntimeTranscoderIndex, StaticModuleIndex, Translator,
13+
ComponentTypes, Export, GlobalInitializer, LoweredIndex, RuntimeAlwaysTrapIndex,
14+
RuntimeTranscoderIndex, StaticModuleIndex, Translator, TypeDef,
1515
};
1616
use wasmtime_environ::{EntityRef, FunctionLoc, ObjectKind, PrimaryMap, ScopeVec, SignatureIndex};
1717
use wasmtime_jit::{CodeMemory, CompiledModuleInfo};
@@ -527,4 +527,62 @@ impl Component {
527527
pub fn serialize(&self) -> Result<Vec<u8>> {
528528
Ok(self.code_object().code_memory().mmap().to_vec())
529529
}
530+
531+
/// Get the names of all the functions exported from the specified instance.
532+
//
533+
// TODO: Eventually we'll want a public API for reflecting the entire
534+
// component type, including the names and types of all its instances,
535+
// imports, and exports. This function is currently only intended for
536+
// discovering wildcard imports.
537+
pub fn function_import_names<'a>(
538+
&'a self,
539+
instance_name: &'a str,
540+
) -> impl Iterator<Item = &str> + 'a {
541+
let env_component = self.env_component();
542+
543+
env_component
544+
.imports
545+
.values()
546+
.filter_map(move |(import, names)| {
547+
let (name, typedef) = &env_component.import_types[*import];
548+
if let (TypeDef::ComponentInstance(_), true) = (typedef, instance_name == name) {
549+
Some(names.iter().map(String::as_str))
550+
} else {
551+
None
552+
}
553+
})
554+
.flatten()
555+
}
556+
557+
/// Get the names of all the functions exported from the specified instance.
558+
//
559+
// TODO: Eventually we'll want a public API for reflecting the entire
560+
// component type, including the names and types of all its instances,
561+
// imports, and exports. This function is currently only intended for
562+
// discovering wildcard exports.
563+
pub fn function_export_names<'a>(
564+
&'a self,
565+
instance_name: &'a str,
566+
) -> impl Iterator<Item = &str> + 'a {
567+
let env_component = self.env_component();
568+
569+
env_component
570+
.exports
571+
.get(instance_name)
572+
.and_then(|export| {
573+
if let Export::Instance(map) = export {
574+
Some(map.iter().filter_map(|(n, e)| {
575+
if let Export::LiftedFunction { .. } = e {
576+
Some(n.as_str())
577+
} else {
578+
None
579+
}
580+
}))
581+
} else {
582+
None
583+
}
584+
})
585+
.into_iter()
586+
.flatten()
587+
}
530588
}

crates/wasmtime/src/component/instance.rs

+23
Original file line numberDiff line numberDiff line change
@@ -672,6 +672,29 @@ impl<'a, 'store> ExportInstance<'a, 'store> {
672672
})
673673
}
674674

675+
/// Returns an iterator of all of the exported functions that this instance
676+
/// contains.
677+
//
678+
// See FIXME in above `modules` method, which also applies here.
679+
pub fn funcs(&mut self) -> impl Iterator<Item = (&'a str, Func)> + '_ {
680+
self.exports
681+
.iter()
682+
.filter_map(|(name, export)| match export {
683+
Export::LiftedFunction { ty, func, options } => Some((
684+
name.as_str(),
685+
Func::from_lifted_func(
686+
self.store,
687+
self.instance,
688+
self.data,
689+
*ty,
690+
func,
691+
options,
692+
),
693+
)),
694+
_ => None,
695+
})
696+
}
697+
675698
fn as_mut(&mut self) -> ExportInstance<'a, '_> {
676699
ExportInstance {
677700
exports: self.exports,

0 commit comments

Comments
 (0)