Skip to content

Commit

Permalink
Squashed and rebased previous work onto HEAD
Browse files Browse the repository at this point in the history
  • Loading branch information
azaslavsky committed May 31, 2024
1 parent acb410e commit 9fdcd8c
Show file tree
Hide file tree
Showing 55 changed files with 2,070 additions and 430 deletions.
3 changes: 2 additions & 1 deletion crates/wit-component/src/encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2157,7 +2157,8 @@ world test {
}
"#,
)
.unwrap(),
.unwrap()
.remove(0),
)
.unwrap();

Expand Down
43 changes: 40 additions & 3 deletions crates/wit-component/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
use std::str::FromStr;
use std::{borrow::Cow, fmt::Display};

use anyhow::{bail, Result};
use anyhow::{bail, Context, Result};
use wasm_encoder::{CanonicalOption, Encode, Section};
use wit_parser::{Resolve, WorldId};
use wit_parser::{parse_use_path, PackageId, ParsedUsePath, Resolve, WorldId};

mod encoding;
mod gc;
Expand Down Expand Up @@ -79,6 +79,43 @@ impl From<StringEncoding> for wasm_encoder::CanonicalOption {
}
}

/// Handles world name resolution for cases when multiple packages may have been resolved. If this
/// is the case, and we're dealing with input that contains a user-supplied world name (like via a
/// CLI command, for instance), we want to ensure that the world name follows the following rules:
///
/// * If there is a single resolved package with a single world, the world name name MAY be
/// omitted.
/// * If there is a single resolved package with multiple worlds, the world name MUST be supplied,
/// but MAY or MAY NOT be fully-qualified.
/// * If there are multiple resolved packages, the world name MUST be fully-qualified.
pub fn resolve_world_from_name(
resolve: &Resolve,
resolved_packages: Vec<PackageId>,
world_name: Option<&str>,
) -> Result<WorldId> {
match resolved_packages.len() {
0 => bail!("all of the supplied WIT source files were empty"),
1 => resolve.select_world(resolved_packages[0], world_name.as_deref()),
_ => match world_name.as_deref() {
Some(name) => {
let world_path = parse_use_path(name).with_context(|| {
format!("failed to parse world specifier `{name}`")
})?;
match world_path {
ParsedUsePath::Name(name) => bail!("the world specifier must be of the fully-qualified, id-based form (ex: \"wasi:http/proxy\" rather than \"proxy\"); you used {name}"),
ParsedUsePath::Package(pkg_name, _) => {
match resolve.package_names.get(&pkg_name) {
Some(pkg_id) => resolve.select_world(pkg_id.clone(), world_name.as_deref()),
None => bail!("the world specifier you provided named {pkg_name}, but no package with that name was found"),
}
}
}
}
None => bail!("the supplied WIT source files describe multiple packages; please provide a fully-qualified world-specifier to the `embed` command"),
},
}
}

/// A producer section to be added to all modules and components synthesized by
/// this crate
pub(crate) fn base_producers() -> wasm_metadata::Producers {
Expand Down Expand Up @@ -147,7 +184,7 @@ world test-world {}

// Parse pre-canned WIT to build resolver
let mut resolver = Resolve::default();
let pkg = UnresolvedPackage::parse(&Path::new("in-code.wit"), COMPONENT_WIT)?;
let pkg = UnresolvedPackage::parse(&Path::new("in-code.wit"), COMPONENT_WIT)?.remove(0);
let pkg_id = resolver.push(pkg)?;
let world = resolver.select_world(pkg_id, Some("test-world").into())?;

Expand Down
10 changes: 5 additions & 5 deletions crates/wit-component/src/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
//! the three arguments originally passed to `encode`.
use crate::validation::BARE_FUNC_MODULE_NAME;
use crate::{DecodedWasm, StringEncoding};
use crate::{resolve_world_from_name, DecodedWasm, StringEncoding};
use anyhow::{bail, Context, Result};
use indexmap::IndexMap;
use std::borrow::Cow;
Expand Down Expand Up @@ -259,12 +259,12 @@ impl Bindgen {
let world_name = reader.read_string()?;
wasm = &data[reader.original_position()..];

let (r, pkg) = match crate::decode(wasm)? {
DecodedWasm::WitPackage(resolve, pkg) => (resolve, pkg),
DecodedWasm::Component(..) => bail!("expected an encoded wit package"),
let (r, pkgs) = match crate::decode(wasm)? {
DecodedWasm::WitPackages(resolve, pkgs) => (resolve, pkgs),
DecodedWasm::Component(..) => bail!("expected encoded wit package(s)"),
};
resolve = r;
world = resolve.packages[pkg].worlds[world_name];
world = resolve_world_from_name(&resolve, pkgs, Some(world_name.into()))?;
}

// Current format where `data` is a wasm component itself.
Expand Down
66 changes: 36 additions & 30 deletions crates/wit-component/src/printing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,37 +50,43 @@ impl WitPrinter {
self
}

/// Print the given WIT package to a string.
pub fn print(&mut self, resolve: &Resolve, pkgid: PackageId) -> Result<String> {
let pkg = &resolve.packages[pkgid];
self.print_docs(&pkg.docs);
self.output.push_str("package ");
self.print_name(&pkg.name.namespace);
self.output.push_str(":");
self.print_name(&pkg.name.name);
if let Some(version) = &pkg.name.version {
self.output.push_str(&format!("@{version}"));
}
self.print_semicolon();
self.output.push_str("\n\n");
for (name, id) in pkg.interfaces.iter() {
self.print_docs(&resolve.interfaces[*id].docs);
self.print_stability(&resolve.interfaces[*id].stability);
self.output.push_str("interface ");
self.print_name(name);
self.output.push_str(" {\n");
self.print_interface(resolve, *id)?;
writeln!(&mut self.output, "}}\n")?;
}
/// Print a set of one or more WIT packages into a string.
pub fn print(&mut self, resolve: &Resolve, pkg_ids: Vec<PackageId>) -> Result<String> {
for (i, pkg_id) in pkg_ids.into_iter().enumerate() {
if i > 0 {
self.output.push_str("\n\n");
}

for (name, id) in pkg.worlds.iter() {
self.print_docs(&resolve.worlds[*id].docs);
self.print_stability(&resolve.worlds[*id].stability);
self.output.push_str("world ");
self.print_name(name);
self.output.push_str(" {\n");
self.print_world(resolve, *id)?;
writeln!(&mut self.output, "}}")?;
let pkg = &resolve.packages[pkg_id];
self.print_docs(&pkg.docs);
self.output.push_str("package ");
self.print_name(&pkg.name.namespace);
self.output.push_str(":");
self.print_name(&pkg.name.name);
if let Some(version) = &pkg.name.version {
self.output.push_str(&format!("@{version}"));
}
self.print_semicolon();
self.output.push_str("\n\n");
for (name, id) in pkg.interfaces.iter() {
self.print_docs(&resolve.interfaces[*id].docs);
self.print_stability(&resolve.interfaces[*id].stability);
self.output.push_str("interface ");
self.print_name(name);
self.output.push_str(" {\n");
self.print_interface(resolve, *id)?;
writeln!(&mut self.output, "}}\n")?;
}

for (name, id) in pkg.worlds.iter() {
self.print_docs(&resolve.worlds[*id].docs);
self.print_stability(&resolve.worlds[*id].stability);
self.output.push_str("world ");
self.print_name(name);
self.output.push_str(" {\n");
self.print_world(resolve, *id)?;
writeln!(&mut self.output, "}}")?;
}
}

Ok(std::mem::take(&mut self.output).into())
Expand Down
14 changes: 13 additions & 1 deletion crates/wit-component/src/semver_check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::{
dummy_module, embed_component_metadata, encoding::encode_world, ComponentEncoder,
StringEncoding,
};
use anyhow::{Context, Result};
use anyhow::{bail, Context, Result};
use wasm_encoder::{ComponentBuilder, ComponentExportKind, ComponentTypeRef};
use wasmparser::{Validator, WasmFeatures};
use wit_parser::{Resolve, WorldId};
Expand Down Expand Up @@ -47,6 +47,18 @@ pub fn semver_check(mut resolve: Resolve, prev: WorldId, new: WorldId) -> Result
pkg.name.version = None;
}

let old_pkg_id = resolve.worlds[prev]
.package
.context("old world not in named package")?;
let old_pkg_name = &resolve.packages[old_pkg_id].name;
let new_pkg_id = resolve.worlds[new]
.package
.context("new world not in named package")?;
let new_pkg_name = &resolve.packages[new_pkg_id].name;
if old_pkg_id != new_pkg_id {
bail!("the old world is in package {old_pkg_name}, which is not the same as the new world, which is in package {new_pkg_name}", )
}

// Component that will be validated at the end.
let mut root_component = ComponentBuilder::default();

Expand Down
Loading

0 comments on commit 9fdcd8c

Please sign in to comment.