Struct wit_parser::Resolve

source ·
pub struct Resolve {
    pub worlds: Arena<World>,
    pub interfaces: Arena<Interface>,
    pub types: Arena<TypeDef>,
    pub packages: Arena<Package>,
    pub package_names: IndexMap<PackageName, PackageId>,
    pub features: IndexSet<String>,
    pub all_features: bool,
}
Expand description

Representation of a fully resolved set of WIT packages.

This structure contains a graph of WIT packages and all of their contents merged together into the contained arenas. All items are sorted topologically and everything here is fully resolved, so with a Resolve no name lookups are necessary and instead everything is index-based.

Working with a WIT package requires inserting it into a Resolve to ensure that all of its dependencies are satisfied. This will give the full picture of that package’s types and such.

Each item in a Resolve has a parent link to trace it back to the original package as necessary.

Fields§

§worlds: Arena<World>

All knowns worlds within this Resolve.

Each world points at a PackageId which is stored below. No ordering is guaranteed between this list of worlds.

§interfaces: Arena<Interface>

All knowns interfaces within this Resolve.

Each interface points at a PackageId which is stored below. No ordering is guaranteed between this list of interfaces.

§types: Arena<TypeDef>

All knowns types within this Resolve.

Types are topologically sorted such that any type referenced from one type is guaranteed to be defined previously. Otherwise though these are not sorted by interface for example.

§packages: Arena<Package>

All knowns packages within this Resolve.

This list of packages is not sorted. Sorted packages can be queried through Resolve::topological_packages.

§package_names: IndexMap<PackageName, PackageId>

A map of package names to the ID of the package with that name.

§features: IndexSet<String>

Activated features for this Resolve.

This set of features is empty by default. This is consulted for @unstable annotations in loaded WIT documents. Any items with @unstable are filtered out unless their feature is present within this set.

§all_features: bool

Activate all features for this Resolve.

Implementations§

source§

impl Resolve

source

pub fn wasm_signature( &self, variant: AbiVariant, func: &Function, ) -> WasmSignature

Get the WebAssembly type signature for this interface function

The first entry returned is the list of parameters and the second entry is the list of results for the wasm function signature.

source

pub fn push_flat(&self, ty: &Type, result: &mut Vec<WasmType>)

Appends the flat wasm types representing ty onto the result list provided.

source§

impl Resolve

source

pub fn new() -> Resolve

Creates a new Resolve with no packages/items inside of it.

source

pub fn push_path( &mut self, path: impl AsRef<Path>, ) -> Result<(Vec<PackageId>, Vec<PathBuf>)>

Parse WIT packages from the input path.

The input path can be one of:

  • A directory containing a WIT package with an optional deps directory for any dependent WIT packages it references.
  • A single standalone WIT file.
  • A wasm-encoded WIT package as a single file in the wasm binary format.
  • A wasm-encoded WIT package as a single file in the wasm text format.

In all of these cases packages are allowed to depend on previously inserted packages into this Resolve. Resolution for packages is based on the name of each package and reference.

This method returns a list of PackageId elements and additionally a list of PathBuf elements. The PackageId elements represent the “main package” that was parsed. For example if a single WIT file was specified this will be all the packages found in the file. For a directory this will be all the packages in the directory itself, but not in the deps directory. The list of PackageId values is useful to pass to Resolve::select_world to take a user-specified world in a conventional fashion and select which to use for bindings generation.

The returned list of PathBuf elements represents all files parsed during this operation. This can be useful for systems that want to rebuild or regenerate bindings based on files modified.

More information can also be found at Resolve::push_dir and Resolve::push_file.

source

pub fn push_dir( &mut self, path: impl AsRef<Path>, ) -> Result<(Vec<PackageId>, Vec<PathBuf>)>

Parses the filesystem directory at path as a WIT package and returns a fully resolved PackageId list as a result.

The directory itself is parsed with UnresolvedPackageGroup::parse_dir and then all packages found are inserted into this Resolve. The path specified may have a deps subdirectory which is probed automatically for any other WIT dependencies.

The deps folder may contain:

  • $path/deps/my-package/*.wit - a directory that may contain multiple WIT files. This is parsed with UnresolvedPackageGroup::parse_dir and then inserted into this Resolve. Note that cannot recursively contain a deps directory.
  • $path/deps/my-package.wit - a single-file WIT package. This is parsed with Resolve::push_file and then added to self for name reoslution.
  • $path/deps/my-package.{wasm,wat} - a wasm-encoded WIT package either in the text for binary format.

In all cases entries in the deps folder are added to self first before adding files found in path itself. All WIT packages found are candidates for name-based resolution that other packages may used.

This function returns a tuple of two values. The first value is a list of PackageId values which represents the WIT packages found within path, but not those within deps. The path provided may contain only a single WIT package but might also use the multi-package form of WIT, and the returned list will indicate which was used. This argument is useful for passing to Resolve::select_world for choosing something to bindgen with.

The second value returned here is the list of paths that were parsed when generating the return value. This can be useful for build systems that want to rebuild bindings whenever one of the files change.

source

pub fn push_file(&mut self, path: impl AsRef<Path>) -> Result<Vec<PackageId>>

Parses the contents of path from the filesystem and pushes the result into this Resolve.

The path referenced here can be one of:

  • A WIT file. Note that in this case this single WIT file will be the entire package and any dependencies it has must already be in self.
  • A WIT package encoded as WebAssembly, either in text or binary form. In this the package and all of its dependencies are automatically inserted into self.

In both situations the PackageIds of the resulting resolved packages are returned from this method. The return value is mostly useful in conjunction with Resolve::select_world.

source

pub fn push( &mut self, unresolved: UnresolvedPackage, source_map: &SourceMap, ) -> Result<PackageId>

Appends a new UnresolvedPackage to this Resolve, creating a fully resolved package with no dangling references.

All the dependencies of unresolved must already have been loaded within this Resolve via previous calls to push or other methods such as Resolve::push_path.

Any dependency resolution error or otherwise world-elaboration error will be returned here, if successful a package identifier is returned which corresponds to the package that was just inserted.

source

pub fn push_group( &mut self, unresolved_groups: UnresolvedPackageGroup, ) -> Result<Vec<PackageId>>

Appends new UnresolvedPackageGroup to this Resolve, creating a fully resolved package with no dangling references.

Any dependency resolution error or otherwise world-elaboration error will be returned here, if successful a package identifier is returned which corresponds to the package that was just inserted.

The returned PackageIds are listed in topologically sorted order.

source

pub fn push_str( &mut self, path: impl AsRef<Path>, contents: &str, ) -> Result<Vec<PackageId>>

Convenience method for combining UnresolvedPackageGroup::parse and Resolve::push_group.

The path provided is used for error messages but otherwise is not read. This method does not touch the filesystem. The contents provided are the contents of a WIT package.

source

pub fn all_bits_valid(&self, ty: &Type) -> bool

source

pub fn merge(&mut self, resolve: Resolve) -> Result<Remap>

Merges all the contents of a different Resolve into this one. The Remap structure returned provides a mapping from all old indices to new indices

This operation can fail if resolve disagrees with self about the packages being inserted. Otherwise though this will additionally attempt to “union” packages found in resolve with those found in self. Unioning packages is keyed on the name/url of packages for those with URLs present. If found then it’s assumed that both Resolve instances were originally created from the same contents and are two views of the same package.

source

pub fn merge_worlds(&mut self, from: WorldId, into: WorldId) -> Result<()>

Merges the world from into the world into.

This will attempt to merge one world into another, unioning all of its imports and exports together. This is an operation performed by wit-component, for example where two different worlds from two different libraries were linked into the same core wasm file and are producing a singular world that will be the final component’s interface.

This operation can fail if the imports/exports overlap.

source

pub fn id_of(&self, interface: InterfaceId) -> Option<String>

Returns the ID of the specified interface.

Returns None for unnamed interfaces.

source

pub fn id_of_name(&self, pkg: PackageId, name: &str) -> String

Returns the ID of the specified name within the pkg.

source

pub fn select_world( &self, packages: &[PackageId], world: Option<&str>, ) -> Result<WorldId>

Attempts to locate a world given the “default” set of packages and the optional string specifier world.

This method is intended to be used by bindings generation tools to select a world from either packages or a package in this Resolve. The packages list is a return value from methods such as push_path, push_dir, push_file, push_group, or push_str. The return values of those methods are the “main package list” which is specified by the user and is used as a heuristic for world selection.

If world is None then packages must have one entry and that package must have exactly one world. If this is the case then that world will be returned, otherwise an error will be returned.

If world is Some then it can either be:

  • A kebab-name of a world such as "the-world". In this situation the packages list must have only a single entry. If packages has no entries or more than one, or if the kebab-name does not exist in the one package specified, then an error will be returned.

  • An ID-based form of a world which is selected within this Resolve, for example "wasi:http/proxy". In this situation the packages array is ignored and the ID specified is use to lookup a package. Note that a version does not need to be specified in this string if there’s only one package of the same name and it has a version. In this situation the version can be omitted.

If successful the corresponding WorldId is returned, otherwise an error is returned.

§Examples
use anyhow::Result;
use wit_parser::Resolve;

fn main() -> Result<()> {
    let mut resolve = Resolve::default();

    // For inputs which have a single package and only one world `None`
    // can be specified.
    let ids = resolve.push_str(
        "./my-test.wit",
        r#"
            package example:wit1;

            world foo {
                // ...
            }
        "#,
    )?;
    assert!(resolve.select_world(&ids, None).is_ok());

    // For inputs which have a single package and multiple worlds then
    // a world must be specified.
    let ids = resolve.push_str(
        "./my-test.wit",
        r#"
            package example:wit2;

            world foo { /* ... */ }

            world bar { /* ... */ }
        "#,
    )?;
    assert!(resolve.select_world(&ids, None).is_err());
    assert!(resolve.select_world(&ids, Some("foo")).is_ok());
    assert!(resolve.select_world(&ids, Some("bar")).is_ok());

    // For inputs which have more than one package then a fully
    // qualified name must be specified.
    let ids = resolve.push_str(
        "./my-test.wit",
        r#"
            package example:wit3 {
                world foo { /* ... */ }
            }

            package example:wit4 {
                world foo { /* ... */ }
            }
        "#,
    )?;
    assert!(resolve.select_world(&ids, None).is_err());
    assert!(resolve.select_world(&ids, Some("foo")).is_err());
    assert!(resolve.select_world(&ids, Some("example:wit3/foo")).is_ok());
    assert!(resolve.select_world(&ids, Some("example:wit4/foo")).is_ok());

    // Note that the `ids` or `packages` argument is ignored if a fully
    // qualified world specified is provided meaning previous worlds
    // can be selected.
    assert!(resolve.select_world(&[], Some("example:wit1/foo")).is_ok());
    assert!(resolve.select_world(&[], Some("example:wit2/foo")).is_ok());

    // When selecting with a version it's ok to drop the version when
    // there's only a single copy of that package in `Resolve`.
    resolve.push_str(
        "./my-test.wit",
        r#"
            package example:wit5@1.0.0;

            world foo { /* ... */ }
        "#,
    )?;
    assert!(resolve.select_world(&[], Some("example:wit5/foo")).is_ok());

    // However when a single package has multiple versions in a resolve
    // it's required to specify the version to select which one.
    resolve.push_str(
        "./my-test.wit",
        r#"
            package example:wit5@2.0.0;

            world foo { /* ... */ }
        "#,
    )?;
    assert!(resolve.select_world(&[], Some("example:wit5/foo")).is_err());
    assert!(resolve.select_world(&[], Some("example:wit5/foo@1.0.0")).is_ok());
    assert!(resolve.select_world(&[], Some("example:wit5/foo@2.0.0")).is_ok());

    Ok(())
}
source

pub fn name_world_key(&self, key: &WorldKey) -> String

Assigns a human readable name to the WorldKey specified.

source

pub fn type_interface_dep(&self, id: TypeId) -> Option<InterfaceId>

Returns the interface that id uses a type from, if it uses a type from a different interface than id is defined within.

If id is not a use-of-a-type or it’s using a type in the same interface then None is returned.

source

pub fn interface_direct_deps( &self, id: InterfaceId, ) -> impl Iterator<Item = InterfaceId> + '_

Returns an iterator of all interfaces that the interface id depends on.

Interfaces may depend on others for type information to resolve type imports.

Note that the returned iterator may yield the same interface as a dependency multiple times. Additionally only direct dependencies of id are yielded, not transitive dependencies.

source

pub fn package_direct_deps( &self, id: PackageId, ) -> impl Iterator<Item = PackageId> + '_

Returns an iterator of all packages that the package id depends on.

Packages may depend on others for type information to resolve type imports or interfaces to resolve worlds.

Note that the returned iterator may yield the same package as a dependency multiple times. Additionally only direct dependencies of id are yielded, not transitive dependencies.

source

pub fn topological_packages(&self) -> Vec<PackageId>

Returns a topological ordering of packages contained in this Resolve.

This returns a list of PackageId such that when visited in order it’s guaranteed that all dependencies will have been defined by prior items in the list.

Trait Implementations§

source§

impl Clone for Resolve

source§

fn clone(&self) -> Resolve

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for Resolve

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Default for Resolve

source§

fn default() -> Resolve

Returns the “default value” for a type. Read more
source§

impl Serialize for Resolve

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> CloneToUninit for T
where T: Clone,

source§

default unsafe fn clone_to_uninit(&self, dst: *mut T)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dst. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> ToOwned for T
where T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.