Skip to content

Commit

Permalink
feat: support semver aware WIT
Browse files Browse the repository at this point in the history
Signed-off-by: Victor Adossi <vadossi@cosmonic.com>
  • Loading branch information
vados-cosmonic committed Jul 23, 2024
1 parent 304312c commit f42c295
Show file tree
Hide file tree
Showing 22 changed files with 876 additions and 247 deletions.
237 changes: 191 additions & 46 deletions Cargo.lock

Large diffs are not rendered by default.

24 changes: 11 additions & 13 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,20 +38,18 @@ anyhow = "1.0.86"
base64 = "0.22.1"
heck = "0.5.0"
js-component-bindgen = { path = "./crates/js-component-bindgen" }
semver = "1.0.23"
structopt = "0.3.26"
wasm-encoder = "0.209.1"
wasm-metadata = "0.209.1"
wasmparser = "0.209.1"
wasmprinter = "0.209.1"
wasmtime-environ = { version = "22.0.0", features = [
"component-model",
"compile",
] }
wat = "1.209.1"
wit-bindgen = "0.26.0"
wit-bindgen-core = "0.26.0"
wit-component = { version = "0.209.1", features = ["dummy-module"] }
wit-parser = "0.209.1"
wasm-encoder = "0.214.0"
wasm-metadata = "0.214.0"
wasmparser = "0.214.0"
wasmprinter = "0.214.0"
wasmtime-environ = { version = "23.0.1", features = ["component-model", "compile"] }
wat = "1.214.0"
wit-bindgen = "0.28.0"
wit-bindgen-core = "0.28.0"
wit-component = { version = "0.214.0", features = ["dummy-module"] }
wit-parser = "0.214.0"
xshell = "0.2.6"

[dev-dependencies]
Expand Down
50 changes: 42 additions & 8 deletions crates/js-component-bindgen-component/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::path::PathBuf;
use anyhow::{Context, Result};
use js_component_bindgen::{
generate_types,
source::wit_parser::{Resolve, UnresolvedPackage},
source::wit_parser::{PackageId, Resolve, UnresolvedPackageGroup},
transpile,
};

Expand Down Expand Up @@ -117,16 +117,41 @@ impl Guest for JsComponentBindgenComponent {
opts: TypeGenerationOptions,
) -> Result<Vec<(String, Vec<u8>)>, String> {
let mut resolve = Resolve::default();
let id = match opts.wit {

// Add features if specified
match opts.features {
Some(EnabledFeatureSet::List(ref features)) => {
for f in features.into_iter() {
resolve.features.insert(f.to_string());
}
}
Some(EnabledFeatureSet::All) => {
resolve.all_features = true;
}
_ => {}
}

let mut pkgs = Vec::<PackageId>::new();
match opts.wit {
Wit::Source(source) => {
let pkg = UnresolvedPackage::parse(&PathBuf::from(format!("{name}.wit")), &source)
let UnresolvedPackageGroup {
packages,
source_map,
} = UnresolvedPackageGroup::parse(&PathBuf::from(format!("{name}.wit")), &source)
.map_err(|e| e.to_string())?;
resolve.push(pkg).map_err(|e| e.to_string())?

for unresolved_pkg in packages {
pkgs.push(
resolve
.push(unresolved_pkg, &source_map)
.map_err(|e| e.to_string())?,
);
}
}
Wit::Path(path) => {
let path = PathBuf::from(path);
if path.is_dir() {
resolve.push_dir(&path).map_err(|e| e.to_string())?.0
pkgs = resolve.push_dir(&path).map_err(|e| e.to_string())?.0;
} else {
let contents = std::fs::read(&path)
.with_context(|| format!("failed to read file {path:?}"))
Expand All @@ -135,16 +160,25 @@ impl Guest for JsComponentBindgenComponent {
Ok(s) => s,
Err(_) => return Err("input file is not valid utf-8".into()),
};
let pkg = UnresolvedPackage::parse(&path, text).map_err(|e| e.to_string())?;
resolve.push(pkg).map_err(|e| e.to_string())?
let UnresolvedPackageGroup {
packages,
source_map,
} = UnresolvedPackageGroup::parse(&path, text).map_err(|e| e.to_string())?;
for unresolved_pkg in packages {
pkgs.push(
resolve
.push(unresolved_pkg, &source_map)
.map_err(|e| e.to_string())?,
);
}
}
}
Wit::Binary(_) => todo!(),
};

let world_string = opts.world.map(|world| world.to_string());
let world = resolve
.select_world(id, world_string.as_deref())
.select_world(&pkgs, world_string.as_deref())
.map_err(|e| e.to_string())?;

let opts = js_component_bindgen::TranspileOpts {
Expand Down
10 changes: 10 additions & 0 deletions crates/js-component-bindgen-component/wit/js-component-bindgen.wit
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,14 @@ world js-component-bindgen {
path(string),
}

/// Enumerate enabled features
variant enabled-feature-set {
/// Enable only the given list of features
%list(list<string>),
/// Enable all features
all,
}

record type-generation-options {
/// wit to generate typing from
wit: wit,
Expand All @@ -81,6 +89,8 @@ world js-component-bindgen {
tla-compat: option<bool>,
instantiation: option<instantiation-mode>,
map: option<maps>,
/// Features that should be enabled as part of feature gating
features: option<enabled-feature-set>,
}

enum export-type {
Expand Down
6 changes: 3 additions & 3 deletions crates/js-component-bindgen/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ transpile-bindgen = []

[dependencies]
anyhow = { workspace = true }
base64 = { workspace = true }
heck = { workspace = true }
semver = { workspace = true }
wasm-encoder = { workspace = true }
wasmparser = { workspace = true }
wasmtime-environ = { workspace = true, features = ['component-model'] }
wit-bindgen-core = { workspace = true }
wit-component = { workspace = true }
wit-parser = { workspace = true }
base64 = { workspace = true }
wasm-encoder = { workspace = true }
11 changes: 5 additions & 6 deletions crates/js-component-bindgen/src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@
use anyhow::{bail, Result};
use std::collections::{HashMap, HashSet};
use wasm_encoder::*;
use wasmparser::collections::IndexMap;
use wasmparser::*;
use wasmtime_environ::component::CoreDef;
use wasmtime_environ::{wasmparser, ModuleTranslation};
Expand Down Expand Up @@ -80,6 +79,7 @@ pub enum AugmentedOp {
F32Store,
F64Store,

#[allow(unused)]
MemorySize,
}

Expand All @@ -91,8 +91,7 @@ impl<'a> Translation<'a> {
let mut features = WasmFeatures::default();
features.set(WasmFeatures::MULTI_MEMORY, false);
match Validator::new_with_features(features).validate_all(translation.wasm) {
// This module validates without multi-memory, no need to augment
// it
// This module validates without multi-memory, no need to augment it
Ok(_) => return Ok(Translation::Normal(translation)),
Err(e) => {
features.set(WasmFeatures::MULTI_MEMORY, true);
Expand Down Expand Up @@ -190,7 +189,7 @@ impl<'a> Translation<'a> {

/// Returns the exports of this module, which are not modified by
/// augmentation.
pub fn exports(&self) -> &IndexMap<String, EntityIndex> {
pub fn exports(&self) -> &wasmparser::collections::IndexMap<String, EntityIndex> {
match self {
Translation::Normal(translation) => &translation.module.exports,
Translation::Augmented { original, .. } => &original.module.exports,
Expand Down Expand Up @@ -704,10 +703,10 @@ macro_rules! define_translate {
});
(mk CallIndirect $ty:ident $table:ident $table_byte:ident) => ({
let _ = $table_byte;
CallIndirect { ty: $ty, table: $table }
CallIndirect { type_index: $ty, table_index: $table }
});
(mk ReturnCallIndirect $ty:ident $table:ident) => (
ReturnCallIndirect { ty: $ty, table: $table }
ReturnCallIndirect { type_index: $ty, table_index: $table }
);
(mk I32Const $v:ident) => (I32Const($v));
(mk I64Const $v:ident) => (I64Const($v));
Expand Down
16 changes: 9 additions & 7 deletions crates/js-component-bindgen/src/function_bindgen.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
use crate::intrinsics::Intrinsic;
use crate::source;
use crate::{uwrite, uwriteln};
use heck::*;
use std::collections::{BTreeMap, BTreeSet};
use std::fmt::Write;
use std::mem;

use heck::*;
use wasmtime_environ::component::{ResourceIndex, TypeResourceTableIndex};
use wit_bindgen_core::abi::{Bindgen, Bitcast, Instruction};
use wit_component::StringEncoding;
use wit_parser::abi::WasmType;
use wit_parser::*;

use wit_bindgen_core::wit_parser::abi::WasmType;
use wit_bindgen_core::wit_parser::{Handle, Resolve, SizeAlign, Type, TypeDefKind, TypeId};

use crate::intrinsics::Intrinsic;
use crate::source;
use crate::{uwrite, uwriteln};

#[derive(PartialEq)]
pub enum ErrHandling {
Expand All @@ -32,7 +35,6 @@ pub enum ResourceData {
},
}

///
/// Map used for resource function bindgen within a given component
///
/// Mapping from the instance + resource index in that component (internal or external)
Expand Down
57 changes: 43 additions & 14 deletions crates/js-component-bindgen/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,28 @@
use anyhow::{bail, Context, Result};
use wasmtime_environ::component::Export;
use wasmtime_environ::component::{ComponentTypesBuilder, StaticModuleIndex};
use wasmtime_environ::wasmparser::Validator;
use wasmtime_environ::{PrimaryMap, ScopeVec, Tunables};
use wit_bindgen_core::wit_parser::{Package, Stability};
use wit_component::DecodedWasm;

mod core;
mod files;
mod transpile_bindgen;
mod ts_bindgen;

pub mod esm_bindgen;
pub mod function_bindgen;
pub mod intrinsics;
pub mod names;
pub mod source;
pub use transpile_bindgen::{BindingsMode, InstantiationMode, TranspileOpts};

use anyhow::Result;
mod transpile_bindgen;
use transpile_bindgen::transpile_bindgen;
pub use transpile_bindgen::{BindingsMode, InstantiationMode, TranspileOpts};

use anyhow::{bail, Context};
use wasmtime_environ::component::Export;
use wasmtime_environ::component::{ComponentTypesBuilder, StaticModuleIndex};
use wasmtime_environ::wasmparser::Validator;
use wasmtime_environ::{PrimaryMap, ScopeVec, Tunables};
use wit_component::DecodedWasm;

mod ts_bindgen;
use ts_bindgen::ts_bindgen;
use wit_parser::{Resolve, Type, TypeDefKind, TypeId, WorldId};

use wit_bindgen_core::wit_parser::{Resolve, Type, TypeDefKind, TypeId, WorldId};

/// Calls [`write!`] with the passed arguments and unwraps the result.
///
Expand Down Expand Up @@ -96,7 +97,7 @@ pub fn transpile(component: &[u8], opts: TranspileOpts) -> Result<Transpiled, an
.context("failed to extract interface information from component")?;

let (resolve, world_id) = match decoded {
DecodedWasm::WitPackage(..) => bail!("unexpected wit package as input"),
DecodedWasm::WitPackages(..) => bail!("unexpected wit package as input"),
DecodedWasm::Component(resolve, world_id) => (resolve, world_id),
};

Expand Down Expand Up @@ -128,7 +129,7 @@ pub fn transpile(component: &[u8], opts: TranspileOpts) -> Result<Transpiled, an
.map(|(_i, module)| core::Translation::new(module, opts.multi_memory))
.collect::<Result<_>>()?;

let types = types.finish(&PrimaryMap::new(), Vec::new(), Vec::new());
let types = types.finish(&wasmtime_environ::component::Component::default());

// Insert all core wasm modules into the generated `Files` which will
// end up getting used in the `generate_instantiate` method.
Expand Down Expand Up @@ -172,3 +173,31 @@ pub fn dealias(resolve: &Resolve, mut id: TypeId) -> TypeId {
}
}
}

/// Check if an item (usually some form of [`WorldItem`]) should be allowed through the feature gate
/// of a given package.
fn feature_gate_allowed(resolve: &Resolve, package: &Package, stability: &Stability) -> bool {
let package_version = package.name.version.as_ref();
if let Stability::Stable { since, feature } = stability {
// If the package version is *before* the @since annotation, exclude this item
if package_version.is_some_and(|v| v < since) {
return false;
}
// If a feature is present but was not enabled explicitly, exclude this item
if feature
.as_ref()
.is_some_and(|f| !resolve.features.contains(f))
{
return false;
}
}

if let Stability::Unstable { feature } = stability {
// If a @unstable feature is present but was not enabled explicitly, exclude this item
if !resolve.features.contains(feature) {
return false;
}
}

return true;
}
2 changes: 1 addition & 1 deletion crates/js-component-bindgen/src/source.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::fmt::{self, Write};
use std::ops::Deref;

pub use wit_parser;
pub use wit_bindgen_core::wit_parser;

#[derive(Default)]
pub struct Source {
Expand Down
Loading

0 comments on commit f42c295

Please sign in to comment.