support dynamic function calls in component model (#4442)
* support dynamic function calls in component model This addresses #4310, introducing a new `component::values::Val` type for representing component values dynamically, as well as `component::types::Type` for representing the corresponding interface types. It also adds a `call` method to `component::func::Func`, which takes a slice of `Val`s as parameters and returns a `Result<Val>` representing the result. Note that I've moved `post_return` and `call_raw` from `TypedFunc` to `Func` since there was nothing specific to `TypedFunc` about them, and I wanted to reuse them. The code in both is unchanged beyond the trivial tweaks to make them fit in their new home. Signed-off-by: Joel Dice <joel.dice@fermyon.com> * order variants and match cases more consistently Signed-off-by: Joel Dice <joel.dice@fermyon.com> * implement lift for String, Box<str>, etc. This also removes the redundant `store` parameter from `Type::load`. Signed-off-by: Joel Dice <joel.dice@fermyon.com> * implement code review feedback This fixes a few issues: - Bad offset calculation when lowering - Missing variant padding - Style issues regarding `types::Handle` - Missed opportunities to reuse `Lift` and `Lower` impls It also adds forwarding `Lift` impls for `Box<[T]>`, `Vec<T>`, etc. Signed-off-by: Joel Dice <joel.dice@fermyon.com> * move `new_*` methods to specific `types` structs Per review feedback, I've moved `Type::new_record` to `Record::new_val` and added a `Type::unwrap_record` method; likewise for the other kinds of types. Signed-off-by: Joel Dice <joel.dice@fermyon.com> * make tuple, option, and expected type comparisons recursive These types should compare as equal across component boundaries as long as their type parameters are equal. Signed-off-by: Joel Dice <joel.dice@fermyon.com> * improve error diagnostic in `Type::check` We now distinguish between more failure cases to provide an informative error message. Signed-off-by: Joel Dice <joel.dice@fermyon.com> * address review feedback - Remove `WasmStr::to_str_from_memory` and `WasmList::get_from_memory` - add `try_new` methods to various `values` types - avoid using `ExactSizeIterator::len` where we can't trust it - fix over-constrained bounds on forwarded `ComponentType` impls Signed-off-by: Joel Dice <joel.dice@fermyon.com> * rearrange code per review feedback - Move functions from `types` to `values` module so we can make certain struct fields private - Rename `try_new` to just `new` Signed-off-by: Joel Dice <joel.dice@fermyon.com> * remove special-case equality test for tuples, options, and expecteds Instead, I've added a FIXME comment and will open an issue to do recursive structural equality testing. Signed-off-by: Joel Dice <joel.dice@fermyon.com>
This commit is contained in:
11
crates/component-util/Cargo.toml
Normal file
11
crates/component-util/Cargo.toml
Normal file
@@ -0,0 +1,11 @@
|
||||
[package]
|
||||
name = "wasmtime-component-util"
|
||||
version = "0.40.0"
|
||||
authors = ["The Wasmtime Project Developers"]
|
||||
description = "Utility types and functions to support the component model in Wasmtime"
|
||||
license = "Apache-2.0 WITH LLVM-exception"
|
||||
repository = "https://github.com/bytecodealliance/wasmtime"
|
||||
documentation = "https://docs.rs/wasmtime-component-util/"
|
||||
categories = ["wasm"]
|
||||
keywords = ["webassembly", "wasm"]
|
||||
edition = "2021"
|
||||
75
crates/component-util/src/lib.rs
Normal file
75
crates/component-util/src/lib.rs
Normal file
@@ -0,0 +1,75 @@
|
||||
/// Represents the possible sizes in bytes of the discriminant of a variant type in the component model
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum DiscriminantSize {
|
||||
/// 8-bit discriminant
|
||||
Size1,
|
||||
/// 16-bit discriminant
|
||||
Size2,
|
||||
/// 32-bit discriminant
|
||||
Size4,
|
||||
}
|
||||
|
||||
impl DiscriminantSize {
|
||||
/// Calculate the size of discriminant needed to represent a variant with the specified number of cases.
|
||||
pub fn from_count(count: usize) -> Option<Self> {
|
||||
if count <= 0xFF {
|
||||
Some(Self::Size1)
|
||||
} else if count <= 0xFFFF {
|
||||
Some(Self::Size2)
|
||||
} else if count <= 0xFFFF_FFFF {
|
||||
Some(Self::Size4)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DiscriminantSize> for u32 {
|
||||
/// Size of the discriminant as a `u32`
|
||||
fn from(size: DiscriminantSize) -> u32 {
|
||||
match size {
|
||||
DiscriminantSize::Size1 => 1,
|
||||
DiscriminantSize::Size2 => 2,
|
||||
DiscriminantSize::Size4 => 4,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DiscriminantSize> for usize {
|
||||
/// Size of the discriminant as a `usize`
|
||||
fn from(size: DiscriminantSize) -> usize {
|
||||
match size {
|
||||
DiscriminantSize::Size1 => 1,
|
||||
DiscriminantSize::Size2 => 2,
|
||||
DiscriminantSize::Size4 => 4,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the number of bytes required to store a flags value in the component model
|
||||
pub enum FlagsSize {
|
||||
/// Flags can fit in a u8
|
||||
Size1,
|
||||
/// Flags can fit in a u16
|
||||
Size2,
|
||||
/// Flags can fit in a specified number of u32 fields
|
||||
Size4Plus(usize),
|
||||
}
|
||||
|
||||
impl FlagsSize {
|
||||
/// Calculate the size needed to represent a value with the specified number of flags.
|
||||
pub fn from_count(count: usize) -> FlagsSize {
|
||||
if count <= 8 {
|
||||
FlagsSize::Size1
|
||||
} else if count <= 16 {
|
||||
FlagsSize::Size2
|
||||
} else {
|
||||
FlagsSize::Size4Plus(ceiling_divide(count, 32))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Divide `n` by `d`, rounding up in the case of a non-zero remainder.
|
||||
fn ceiling_divide(n: usize, d: usize) -> usize {
|
||||
(n + d - 1) / d
|
||||
}
|
||||
Reference in New Issue
Block a user