Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 18 additions & 8 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@ bitflags = "1.3.2"
heck = "0.3"
pulldown-cmark = { version = "0.8", default-features = false }
clap = { version = "4.0.9", features = ["derive"] }
env_logger = "0.9.1"

wasmtime = "1.0"
wasmtime-wasi = "1.0"
wasmprinter = "0.2.40"
wasmparser = "0.91.0"
wasm-encoder = "0.17.0"
wasmprinter = "0.2.41"
wasmparser = "0.92.0"
wasm-encoder = "0.18.0"
wat = "1.0.49"

wit-bindgen-core = { path = 'crates/bindgen-core', version = '0.2.0' }
Expand All @@ -42,6 +43,7 @@ wit-bindgen-gen-rust-lib = { path = 'crates/gen-rust-lib', version = '0.2.0' }
wit-bindgen-guest-rust = { path = 'crates/guest-rust', version = '0.2.0' }
wit-bindgen-host-wasmtime-rust = { path = 'crates/host-wasmtime-rust', version = '0.2.0' }
wit-parser = { path = 'crates/wit-parser', version = '0.2.0' }
wit-component = { path = 'crates/wit-component', version = '0.2.0' }

[[bin]]
name = "wit-bindgen"
Expand Down
1 change: 1 addition & 0 deletions crates/test-helpers/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ filetime = "0.2"
wit-bindgen-gen-guest-c = { workspace = true }
wit-bindgen-gen-guest-teavm-java = { workspace = true }
wit-bindgen-core = { workspace = true }
wit-component = { workspace = true }

[features]
default = ['guest-rust', 'guest-c', 'guest-teavm-java', 'host-js', 'host-wasmtime-py', 'host-wasmtime-rust']
Expand Down
3 changes: 2 additions & 1 deletion crates/wit-component/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,15 @@ wit-parser = { workspace = true }
anyhow = { workspace = true }
indexmap = "1.9.1"
clap = { workspace = true, optional = true }
env_logger = { version = "0.9.1", optional = true }
env_logger = { workspace = true, optional = true }
log = { version = "0.4.17", optional = true }
bitflags = { workspace = true }

[dev-dependencies]
wasmprinter = { workspace = true }
glob = "0.3.0"
pretty_assertions = "1.3.0"
env_logger = { workspace = true }

[features]
default = ["cli"]
Expand Down
63 changes: 57 additions & 6 deletions crates/wit-component/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,24 @@ use clap::Parser;
use std::path::{Path, PathBuf};
use wit_parser::Interface;

fn parse_named_interface(s: &str) -> Result<Interface> {
let (name, path) = s
.split_once('=')
.ok_or_else(|| anyhow::anyhow!("expected a value with format `NAME=INTERFACE`"))?;
fn parse_optionally_name_file(s: &str) -> (&str, &str) {
let mut parts = s.splitn(2, '=');
let name_or_path = parts.next().unwrap();
match parts.next() {
Some(path) => (name_or_path, path),
None => {
let name = Path::new(name_or_path)
.file_stem()
.unwrap()
.to_str()
.unwrap();
(name, name_or_path)
}
}
}

fn parse_named_interface(s: &str) -> Result<Interface> {
let (name, path) = parse_optionally_name_file(s);
parse_interface(Some(name.to_string()), Path::new(path))
}

Expand All @@ -36,20 +49,54 @@ fn parse_interface(name: Option<String>, path: &Path) -> Result<Interface> {
Ok(interface)
}

fn parse_adapter(s: &str) -> Result<(String, Vec<u8>, Interface)> {
let mut parts = s.splitn(2, ':');
let maybe_named_module = parts.next().unwrap();
let (name, path) = parse_optionally_name_file(maybe_named_module);
let wasm = wat::parse_file(path)?;

match parts.next() {
Some(maybe_named_interface) => {
let interface = parse_named_interface(maybe_named_interface)?;
Ok((name.to_string(), wasm, interface))
}
None => {
// TODO: implement inferring the `interface` from the `wasm`
// specified
drop((name, wasm));
bail!("inferring from the core wasm module is not supported at this time")
}
}
}

/// WebAssembly component encoder.
///
/// Encodes a WebAssembly component from a core WebAssembly module.
#[derive(Debug, Parser)]
#[clap(name = "component-encoder", version = env!("CARGO_PKG_VERSION"))]
pub struct WitComponentApp {
/// The path to an interface definition file the component imports.
#[clap(long = "import", value_name = "NAME=INTERFACE", value_parser = parse_named_interface)]
#[clap(long = "import", value_name = "[NAME=]INTERFACE", value_parser = parse_named_interface)]
pub imports: Vec<Interface>,

/// The path to an interface definition file the component exports.
#[clap(long = "export", value_name = "NAME=INTERFACE", value_parser = parse_named_interface)]
#[clap(long = "export", value_name = "[NAME=]INTERFACE", value_parser = parse_named_interface)]
pub exports: Vec<Interface>,

/// The path to an adapter module to satisfy imports.
///
/// An adapter module can be used to translate the `wasi_snapshot_preview1`
/// ABI, for example, to one that uses the component model. The first
/// `[NAME=]` specified in the argument is inferred from the name of file
/// specified by `MODULE` if not present and is the name of the import
/// module that's being implemented (e.g. `wasi_snapshot_preview1.wasm`.
///
/// The second part of this argument, optionally specified, is the interface
/// that this adapter module imports. If not specified then the interface
/// imported is inferred from the adapter module itself.
#[clap(long = "adapt", value_name = "[NAME=]MODULE[:[NAME=]INTERFACE]", value_parser = parse_adapter)]
pub adapters: Vec<(String, Vec<u8>, Interface)>,

/// The path of the output WebAssembly component.
#[clap(long, short = 'o', value_name = "OUTPUT")]
pub output: Option<PathBuf>,
Expand Down Expand Up @@ -97,6 +144,10 @@ impl WitComponentApp {
.exports(&self.exports)
.validate(!self.skip_validation);

for (name, wasm, interface) in self.adapters.iter() {
encoder = encoder.adapter(name, wasm, interface);
}

if let Some(interface) = &self.interface {
encoder = encoder.interface(interface);
}
Expand Down
Loading