Upgrade wasm-tools crates, namely the component model (#4715)
* Upgrade wasm-tools crates, namely the component model This commit pulls in the latest versions of all of the `wasm-tools` family of crates. There were two major changes that happened in `wasm-tools` in the meantime: * bytecodealliance/wasm-tools#697 - this commit introduced a new API for more efficiently reading binary operators from a wasm binary. The old `Operator`-based reading was left in place, however, and continues to be what Wasmtime uses. I hope to update Wasmtime in a future PR to use this new API, but for now the biggest change is... * bytecodealliance/wasm-tools#703 - this commit was a major update to the component model AST. This commit almost entirely deals with the fallout of this change. The changes made to the component model were: 1. The `unit` type no longer exists. This was generally a simple change where the `Unit` case in a few different locations were all removed. 2. The `expected` type was renamed to `result`. This similarly was relatively lightweight and mostly just a renaming on the surface. I took this opportunity to rename `val::Result` to `val::ResultVal` and `types::Result` to `types::ResultType` to avoid clashing with the standard library types. The `Option`-based types were handled with this as well. 3. The payload type of `variant` and `result` types are now optional. This affected many locations that calculate flat type representations, ABI information, etc. The `#[derive(ComponentType)]` macro now specifically handles Rust-defined `enum` types which have no payload to the equivalent in the component model. 4. Functions can now return multiple parameters. This changed the signature of invoking component functions because the return value is now bound by `ComponentNamedList` (renamed from `ComponentParams`). This had a large effect in the tests, fuzz test case generation, etc. 5. Function types with 2-or-more parameters/results must uniquely name all parameters/results. This mostly affected the text format used throughout the tests. I haven't added specifically new tests for multi-return but I changed a number of tests to use it. Additionally I've updated the fuzzers to all exercise multi-return as well so I think we should get some good coverage with that. * Update version numbers * Use crates.io
This commit is contained in:
@@ -22,7 +22,7 @@ wasmtime-cranelift = { path = "../cranelift", version = "=0.41.0", optional = tr
|
||||
wasmtime-component-macro = { path = "../component-macro", version = "=0.41.0", optional = true }
|
||||
wasmtime-component-util = { path = "../component-util", version = "=0.41.0", optional = true }
|
||||
target-lexicon = { version = "0.12.0", default-features = false }
|
||||
wasmparser = "0.88.0"
|
||||
wasmparser = "0.89.0"
|
||||
anyhow = "1.0.19"
|
||||
libc = "0.2"
|
||||
cfg-if = "1.0"
|
||||
|
||||
@@ -198,8 +198,8 @@ impl Func {
|
||||
/// # use wasmtime::component::Func;
|
||||
/// # use wasmtime::Store;
|
||||
/// # fn foo(func: &Func, mut store: Store<()>) -> anyhow::Result<()> {
|
||||
/// let typed = func.typed::<(&str,), String, _>(&store)?;
|
||||
/// let ret = typed.call(&mut store, ("Hello, ",))?;
|
||||
/// let typed = func.typed::<(&str,), (String,), _>(&store)?;
|
||||
/// let ret = typed.call(&mut store, ("Hello, ",))?.0;
|
||||
/// println!("returned string was: {}", ret);
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
@@ -211,16 +211,16 @@ impl Func {
|
||||
/// # use wasmtime::component::Func;
|
||||
/// # use wasmtime::Store;
|
||||
/// # fn foo(func: &Func, mut store: Store<()>) -> anyhow::Result<()> {
|
||||
/// let typed = func.typed::<(u32, Option<&str>, &[u8]), bool, _>(&store)?;
|
||||
/// let ok: bool = typed.call(&mut store, (1, Some("hello"), b"bytes!"))?;
|
||||
/// let typed = func.typed::<(u32, Option<&str>, &[u8]), (bool,), _>(&store)?;
|
||||
/// let ok: bool = typed.call(&mut store, (1, Some("hello"), b"bytes!"))?.0;
|
||||
/// println!("return value was: {ok}");
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn typed<Params, Return, S>(&self, store: S) -> Result<TypedFunc<Params, Return>>
|
||||
where
|
||||
Params: ComponentParams + Lower,
|
||||
Return: Lift,
|
||||
Params: ComponentNamedList + Lower,
|
||||
Return: ComponentNamedList + Lift,
|
||||
S: AsContext,
|
||||
{
|
||||
self._typed(store.as_context().0)
|
||||
@@ -231,8 +231,8 @@ impl Func {
|
||||
store: &StoreOpaque,
|
||||
) -> Result<TypedFunc<Params, Return>>
|
||||
where
|
||||
Params: ComponentParams + Lower,
|
||||
Return: Lift,
|
||||
Params: ComponentNamedList + Lower,
|
||||
Return: ComponentNamedList + Lift,
|
||||
{
|
||||
self.typecheck::<Params, Return>(store)?;
|
||||
unsafe { Ok(TypedFunc::new_unchecked(*self)) }
|
||||
@@ -240,15 +240,16 @@ impl Func {
|
||||
|
||||
fn typecheck<Params, Return>(&self, store: &StoreOpaque) -> Result<()>
|
||||
where
|
||||
Params: ComponentParams + Lower,
|
||||
Return: Lift,
|
||||
Params: ComponentNamedList + Lower,
|
||||
Return: ComponentNamedList + Lift,
|
||||
{
|
||||
let data = &store[self.0];
|
||||
let ty = &data.types[data.ty];
|
||||
|
||||
Params::typecheck_params(&ty.params, &data.types)
|
||||
Params::typecheck_named_list(&ty.params, &data.types)
|
||||
.context("type mismatch with parameters")?;
|
||||
Return::typecheck(&ty.result, &data.types).context("type mismatch with result")?;
|
||||
Return::typecheck_named_list(&ty.results, &data.types)
|
||||
.context("type mismatch with results")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -263,10 +264,14 @@ impl Func {
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Get the result type for this function.
|
||||
pub fn result(&self, store: impl AsContext) -> Type {
|
||||
/// Get the result types for this function.
|
||||
pub fn results(&self, store: impl AsContext) -> Box<[Type]> {
|
||||
let data = &store.as_context()[self.0];
|
||||
Type::from(&data.types[data.ty].result, &data.types)
|
||||
data.types[data.ty]
|
||||
.results
|
||||
.iter()
|
||||
.map(|(_, ty)| Type::from(ty, &data.types))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Invokes this function with the `params` given and returns the result.
|
||||
@@ -274,64 +279,71 @@ impl Func {
|
||||
/// The `params` here must match the type signature of this `Func`, or this will return an error. If a trap
|
||||
/// occurs while executing this function, then an error will also be returned.
|
||||
// TODO: say more -- most of the docs for `TypedFunc::call` apply here, too
|
||||
pub fn call(&self, mut store: impl AsContextMut, args: &[Val]) -> Result<Val> {
|
||||
pub fn call(
|
||||
&self,
|
||||
mut store: impl AsContextMut,
|
||||
params: &[Val],
|
||||
results: &mut [Val],
|
||||
) -> Result<()> {
|
||||
let store = &mut store.as_context_mut();
|
||||
|
||||
let params;
|
||||
let result;
|
||||
let param_tys = self.params(&store);
|
||||
let result_tys = self.results(&store);
|
||||
|
||||
{
|
||||
let data = &store[self.0];
|
||||
let ty = &data.types[data.ty];
|
||||
|
||||
if ty.params.len() != args.len() {
|
||||
bail!(
|
||||
"expected {} argument(s), got {}",
|
||||
ty.params.len(),
|
||||
args.len()
|
||||
);
|
||||
}
|
||||
|
||||
params = ty
|
||||
.params
|
||||
.iter()
|
||||
.zip(args)
|
||||
.map(|((_, ty), arg)| {
|
||||
let ty = Type::from(ty, &data.types);
|
||||
|
||||
ty.check(arg).context("type mismatch with parameters")?;
|
||||
|
||||
Ok(ty)
|
||||
})
|
||||
.collect::<Result<Vec<_>>>()?;
|
||||
|
||||
result = Type::from(&ty.result, &data.types);
|
||||
if param_tys.len() != params.len() {
|
||||
bail!(
|
||||
"expected {} argument(s), got {}",
|
||||
param_tys.len(),
|
||||
params.len()
|
||||
);
|
||||
}
|
||||
if result_tys.len() != results.len() {
|
||||
bail!(
|
||||
"expected {} results(s), got {}",
|
||||
result_tys.len(),
|
||||
results.len()
|
||||
);
|
||||
}
|
||||
|
||||
let param_abi = CanonicalAbiInfo::record(params.iter().map(|t| t.canonical_abi()));
|
||||
let result_count = result.canonical_abi().flat_count(MAX_FLAT_RESULTS);
|
||||
for (param, ty) in params.iter().zip(param_tys.iter()) {
|
||||
ty.check(param).context("type mismatch with parameters")?;
|
||||
}
|
||||
|
||||
let param_abi = CanonicalAbiInfo::record(param_tys.iter().map(|t| t.canonical_abi()));
|
||||
let result_abi = CanonicalAbiInfo::record(result_tys.iter().map(|t| t.canonical_abi()));
|
||||
|
||||
self.call_raw(
|
||||
store,
|
||||
args,
|
||||
|store, options, args, dst: &mut MaybeUninit<[ValRaw; MAX_FLAT_PARAMS]>| {
|
||||
if param_abi.flat_count(MAX_FLAT_PARAMS).is_none() {
|
||||
self.store_args(store, &options, ¶m_abi, ¶ms, args, dst)
|
||||
} else {
|
||||
params,
|
||||
|store, options, params, dst: &mut MaybeUninit<[ValRaw; MAX_FLAT_PARAMS]>| {
|
||||
if param_abi.flat_count(MAX_FLAT_PARAMS).is_some() {
|
||||
let dst = &mut unsafe {
|
||||
mem::transmute::<_, &mut [MaybeUninit<ValRaw>; MAX_FLAT_PARAMS]>(dst)
|
||||
}
|
||||
.iter_mut();
|
||||
|
||||
args.iter()
|
||||
.try_for_each(|arg| arg.lower(store, &options, dst))
|
||||
params
|
||||
.iter()
|
||||
.try_for_each(|param| param.lower(store, &options, dst))
|
||||
} else {
|
||||
self.store_args(store, &options, ¶m_abi, ¶m_tys, params, dst)
|
||||
}
|
||||
},
|
||||
|store, options, src: &[ValRaw; MAX_FLAT_RESULTS]| {
|
||||
if result_count.is_none() {
|
||||
Self::load_result(&Memory::new(store, &options), &result, &mut src.iter())
|
||||
if result_abi.flat_count(MAX_FLAT_RESULTS).is_some() {
|
||||
let mut flat = src.iter();
|
||||
for (ty, slot) in result_tys.iter().zip(results) {
|
||||
*slot = Val::lift(ty, store, &options, &mut flat)?;
|
||||
}
|
||||
Ok(())
|
||||
} else {
|
||||
Val::lift(&result, store, &options, &mut src.iter())
|
||||
Self::load_results(
|
||||
&Memory::new(store, &options),
|
||||
&result_abi,
|
||||
&result_tys,
|
||||
results,
|
||||
&mut src.iter(),
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
@@ -567,12 +579,13 @@ impl Func {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn load_result<'a>(
|
||||
fn load_results<'a>(
|
||||
mem: &Memory,
|
||||
ty: &Type,
|
||||
abi: &CanonicalAbiInfo,
|
||||
result_tys: &[Type],
|
||||
results: &mut [Val],
|
||||
src: &mut std::slice::Iter<'_, ValRaw>,
|
||||
) -> Result<Val> {
|
||||
let abi = ty.canonical_abi();
|
||||
) -> Result<()> {
|
||||
// FIXME: needs to read an i64 for memory64
|
||||
let ptr = usize::try_from(src.next().unwrap().get_u32())?;
|
||||
if ptr % usize::try_from(abi.align32)? != 0 {
|
||||
@@ -585,6 +598,12 @@ impl Func {
|
||||
.and_then(|b| b.get(..usize::try_from(abi.size32).unwrap()))
|
||||
.ok_or_else(|| anyhow::anyhow!("pointer out of bounds of memory"))?;
|
||||
|
||||
Val::load(ty, mem, bytes)
|
||||
let mut offset = 0;
|
||||
for (ty, slot) in result_tys.iter().zip(results) {
|
||||
let abi = ty.canonical_abi();
|
||||
let offset = abi.next_field32_size(&mut offset);
|
||||
*slot = Val::load(ty, mem, &bytes[offset..][..abi.size32 as usize])?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::component::func::{Memory, MemoryMut, Options};
|
||||
use crate::component::storage::slice_to_storage_mut;
|
||||
use crate::component::{ComponentParams, ComponentType, Lift, Lower, Type, Val};
|
||||
use crate::component::{ComponentNamedList, ComponentType, Lift, Lower, Type, Val};
|
||||
use crate::{AsContextMut, StoreContextMut, ValRaw};
|
||||
use anyhow::{anyhow, bail, Context, Result};
|
||||
use std::any::Any;
|
||||
@@ -53,8 +53,8 @@ impl HostFunc {
|
||||
fn new<F, P, R>(func: F, entrypoint: VMLoweringCallee) -> Arc<HostFunc>
|
||||
where
|
||||
F: Send + Sync + 'static,
|
||||
P: ComponentParams + Lift + 'static,
|
||||
R: Lower + 'static,
|
||||
P: ComponentNamedList + Lift + 'static,
|
||||
R: ComponentNamedList + Lower + 'static,
|
||||
{
|
||||
Arc::new(HostFunc {
|
||||
entrypoint,
|
||||
@@ -63,14 +63,14 @@ impl HostFunc {
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn new_dynamic<
|
||||
T,
|
||||
F: Fn(StoreContextMut<'_, T>, &[Val]) -> Result<Val> + Send + Sync + 'static,
|
||||
>(
|
||||
pub(crate) fn new_dynamic<T, F>(
|
||||
func: F,
|
||||
index: TypeFuncIndex,
|
||||
types: &Arc<ComponentTypes>,
|
||||
) -> Arc<HostFunc> {
|
||||
) -> Arc<HostFunc>
|
||||
where
|
||||
F: Fn(StoreContextMut<'_, T>, &[Val], &mut [Val]) -> Result<()> + Send + Sync + 'static,
|
||||
{
|
||||
let ty = &types[index];
|
||||
|
||||
Arc::new(HostFunc {
|
||||
@@ -94,7 +94,11 @@ impl HostFunc {
|
||||
.iter()
|
||||
.map(|(_, ty)| Type::from(ty, types))
|
||||
.collect(),
|
||||
result: Type::from(&ty.result, types),
|
||||
results: ty
|
||||
.results
|
||||
.iter()
|
||||
.map(|(_, ty)| Type::from(ty, types))
|
||||
.collect(),
|
||||
},
|
||||
}),
|
||||
})
|
||||
@@ -115,12 +119,12 @@ impl HostFunc {
|
||||
|
||||
fn typecheck<P, R>(ty: TypeFuncIndex, types: &Arc<ComponentTypes>) -> Result<()>
|
||||
where
|
||||
P: ComponentParams + Lift,
|
||||
R: Lower,
|
||||
P: ComponentNamedList + Lift,
|
||||
R: ComponentNamedList + Lower,
|
||||
{
|
||||
let ty = &types[ty];
|
||||
P::typecheck_params(&ty.params, types).context("type mismatch with parameters")?;
|
||||
R::typecheck(&ty.result, types).context("type mismatch with result")?;
|
||||
P::typecheck_named_list(&ty.params, types).context("type mismatch with parameters")?;
|
||||
R::typecheck_named_list(&ty.results, types).context("type mismatch with results")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -281,8 +285,8 @@ macro_rules! impl_into_component_func {
|
||||
impl<T, F, $($args,)* R> IntoComponentFunc<T, ($($args,)*), R> for F
|
||||
where
|
||||
F: Fn($($args),*) -> Result<R> + Send + Sync + 'static,
|
||||
($($args,)*): ComponentParams + Lift + 'static,
|
||||
R: Lower + 'static,
|
||||
($($args,)*): ComponentNamedList + Lift + 'static,
|
||||
R: ComponentNamedList + Lower + 'static,
|
||||
{
|
||||
extern "C" fn entrypoint(
|
||||
cx: *mut VMOpaqueContext,
|
||||
@@ -319,8 +323,8 @@ macro_rules! impl_into_component_func {
|
||||
impl<T, F, $($args,)* R> IntoComponentFunc<T, (StoreContextMut<'_, T>, $($args,)*), R> for F
|
||||
where
|
||||
F: Fn(StoreContextMut<'_, T>, $($args),*) -> Result<R> + Send + Sync + 'static,
|
||||
($($args,)*): ComponentParams + Lift + 'static,
|
||||
R: Lower + 'static,
|
||||
($($args,)*): ComponentNamedList + Lift + 'static,
|
||||
R: ComponentNamedList + Lower + 'static,
|
||||
{
|
||||
extern "C" fn entrypoint(
|
||||
cx: *mut VMOpaqueContext,
|
||||
@@ -357,7 +361,7 @@ macro_rules! impl_into_component_func {
|
||||
for_each_function_signature!(impl_into_component_func);
|
||||
|
||||
unsafe fn call_host_dynamic<T, F>(
|
||||
Types { params, result }: &Types,
|
||||
Types { params, results }: &Types,
|
||||
cx: *mut VMOpaqueContext,
|
||||
mut flags: InstanceFlags,
|
||||
memory: *mut VMMemoryDefinition,
|
||||
@@ -367,7 +371,7 @@ unsafe fn call_host_dynamic<T, F>(
|
||||
closure: F,
|
||||
) -> Result<()>
|
||||
where
|
||||
F: FnOnce(StoreContextMut<'_, T>, &[Val]) -> Result<Val>,
|
||||
F: FnOnce(StoreContextMut<'_, T>, &[Val], &mut [Val]) -> Result<()>,
|
||||
{
|
||||
let cx = VMComponentContext::from_opaque(cx);
|
||||
let instance = (*cx).instance();
|
||||
@@ -391,15 +395,7 @@ where
|
||||
let ret_index;
|
||||
|
||||
let param_abi = CanonicalAbiInfo::record(params.iter().map(|t| t.canonical_abi()));
|
||||
let param_count = param_abi.flat_count.and_then(|i| {
|
||||
let i = usize::from(i);
|
||||
if i > MAX_FLAT_PARAMS {
|
||||
None
|
||||
} else {
|
||||
Some(i)
|
||||
}
|
||||
});
|
||||
if let Some(param_count) = param_count {
|
||||
if let Some(param_count) = param_abi.flat_count(MAX_FLAT_PARAMS) {
|
||||
let iter = &mut storage.iter();
|
||||
args = params
|
||||
.iter()
|
||||
@@ -424,20 +420,31 @@ where
|
||||
ret_index = 1;
|
||||
};
|
||||
|
||||
let ret = closure(cx.as_context_mut(), &args)?;
|
||||
let mut result_vals = Vec::with_capacity(results.len());
|
||||
for _ in results.iter() {
|
||||
result_vals.push(Val::Bool(false));
|
||||
}
|
||||
closure(cx.as_context_mut(), &args, &mut result_vals)?;
|
||||
flags.set_may_leave(false);
|
||||
result.check(&ret)?;
|
||||
for (val, ty) in result_vals.iter().zip(results.iter()) {
|
||||
ty.check(val)?;
|
||||
}
|
||||
|
||||
let result_count = result.canonical_abi().flat_count(MAX_FLAT_RESULTS);
|
||||
if result_count.is_some() {
|
||||
let result_abi = CanonicalAbiInfo::record(results.iter().map(|t| t.canonical_abi()));
|
||||
if result_abi.flat_count(MAX_FLAT_RESULTS).is_some() {
|
||||
let dst = mem::transmute::<&mut [ValRaw], &mut [MaybeUninit<ValRaw>]>(storage);
|
||||
ret.lower(&mut cx, &options, &mut dst.iter_mut())?;
|
||||
let mut dst = dst.iter_mut();
|
||||
for val in result_vals.iter() {
|
||||
val.lower(&mut cx, &options, &mut dst)?;
|
||||
}
|
||||
} else {
|
||||
let ret_ptr = &storage[ret_index];
|
||||
let mut memory = MemoryMut::new(cx.as_context_mut(), &options);
|
||||
let ptr =
|
||||
validate_inbounds_dynamic(result.canonical_abi(), memory.as_slice_mut(), ret_ptr)?;
|
||||
ret.store(&mut memory, ptr)?;
|
||||
let mut ptr = validate_inbounds_dynamic(&result_abi, memory.as_slice_mut(), ret_ptr)?;
|
||||
for (val, ty) in result_vals.iter().zip(results.iter()) {
|
||||
let offset = ty.canonical_abi().next_field32_size(&mut ptr);
|
||||
val.store(&mut memory, offset)?;
|
||||
}
|
||||
}
|
||||
|
||||
flags.set_may_leave(true);
|
||||
@@ -463,7 +470,7 @@ fn validate_inbounds_dynamic(abi: &CanonicalAbiInfo, memory: &[u8], ptr: &ValRaw
|
||||
|
||||
struct Types {
|
||||
params: Box<[Type]>,
|
||||
result: Type,
|
||||
results: Box<[Type]>,
|
||||
}
|
||||
|
||||
struct DynamicContext<F> {
|
||||
@@ -471,10 +478,7 @@ struct DynamicContext<F> {
|
||||
types: Types,
|
||||
}
|
||||
|
||||
extern "C" fn dynamic_entrypoint<
|
||||
T,
|
||||
F: Fn(StoreContextMut<'_, T>, &[Val]) -> Result<Val> + Send + Sync + 'static,
|
||||
>(
|
||||
extern "C" fn dynamic_entrypoint<T, F>(
|
||||
cx: *mut VMOpaqueContext,
|
||||
data: *mut u8,
|
||||
flags: InstanceFlags,
|
||||
@@ -483,7 +487,9 @@ extern "C" fn dynamic_entrypoint<
|
||||
string_encoding: StringEncoding,
|
||||
storage: *mut ValRaw,
|
||||
storage_len: usize,
|
||||
) {
|
||||
) where
|
||||
F: Fn(StoreContextMut<'_, T>, &[Val], &mut [Val]) -> Result<()> + Send + Sync + 'static,
|
||||
{
|
||||
let data = data as *const DynamicContext<F>;
|
||||
unsafe {
|
||||
handle_result(|| {
|
||||
@@ -495,7 +501,7 @@ extern "C" fn dynamic_entrypoint<
|
||||
realloc,
|
||||
string_encoding,
|
||||
std::slice::from_raw_parts_mut(storage, storage_len),
|
||||
|store, values| ((*data).func)(store, values),
|
||||
|store, params, results| ((*data).func)(store, params, results),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ impl<Params, Return> Clone for TypedFunc<Params, Return> {
|
||||
|
||||
impl<Params, Return> TypedFunc<Params, Return>
|
||||
where
|
||||
Params: ComponentParams + Lower,
|
||||
Params: ComponentNamedList + Lower,
|
||||
Return: Lift,
|
||||
{
|
||||
/// Creates a new [`TypedFunc`] from the provided component [`Func`],
|
||||
@@ -288,8 +288,8 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// A trait representing a static list of parameters that can be passed to a
|
||||
/// [`TypedFunc`].
|
||||
/// A trait representing a static list of named types that can be passed to or
|
||||
/// returned from a [`TypedFunc`].
|
||||
///
|
||||
/// This trait is implemented for a number of tuple types and is not expected
|
||||
/// to be implemented externally. The contents of this trait are hidden as it's
|
||||
@@ -304,11 +304,11 @@ where
|
||||
// would not be memory safe. The main reason this is `unsafe` is the
|
||||
// `typecheck` function which must operate correctly relative to the `AsTuple`
|
||||
// interpretation of the implementor.
|
||||
pub unsafe trait ComponentParams: ComponentType {
|
||||
/// Performs a typecheck to ensure that this `ComponentParams` implementor
|
||||
/// matches the types of the types in `params`.
|
||||
pub unsafe trait ComponentNamedList: ComponentType {
|
||||
/// Performs a typecheck to ensure that this `ComponentNamedList`
|
||||
/// implementor matches the types of the types in `params`.
|
||||
#[doc(hidden)]
|
||||
fn typecheck_params(
|
||||
fn typecheck_named_list(
|
||||
params: &[(Option<String>, InterfaceType)],
|
||||
types: &ComponentTypes,
|
||||
) -> Result<()>;
|
||||
@@ -374,6 +374,9 @@ pub unsafe trait ComponentType {
|
||||
#[doc(hidden)]
|
||||
const ALIGN32: u32 = Self::ABI.align32;
|
||||
|
||||
#[doc(hidden)]
|
||||
const IS_RUST_UNIT_TYPE: bool = false;
|
||||
|
||||
/// Returns the number of core wasm abi values will be used to represent
|
||||
/// this type in its lowered form.
|
||||
///
|
||||
@@ -393,7 +396,7 @@ pub unsafe trait ComponentType {
|
||||
|
||||
#[doc(hidden)]
|
||||
pub unsafe trait ComponentVariant: ComponentType {
|
||||
const CASES: &'static [CanonicalAbiInfo];
|
||||
const CASES: &'static [Option<CanonicalAbiInfo>];
|
||||
const INFO: VariantInfo = VariantInfo::new_static(Self::CASES);
|
||||
const PAYLOAD_OFFSET32: usize = Self::INFO.payload_offset32 as usize;
|
||||
}
|
||||
@@ -1352,16 +1355,9 @@ fn typecheck_tuple(
|
||||
expected: &[fn(&InterfaceType, &ComponentTypes) -> Result<()>],
|
||||
) -> Result<()> {
|
||||
match ty {
|
||||
InterfaceType::Unit if expected.len() == 0 => Ok(()),
|
||||
InterfaceType::Tuple(t) => {
|
||||
let tuple = &types[*t];
|
||||
if tuple.types.len() != expected.len() {
|
||||
if expected.len() == 0 {
|
||||
bail!(
|
||||
"expected unit or 0-tuple, found {}-tuple",
|
||||
tuple.types.len(),
|
||||
);
|
||||
}
|
||||
bail!(
|
||||
"expected {}-tuple, found {}-tuple",
|
||||
expected.len(),
|
||||
@@ -1373,9 +1369,6 @@ fn typecheck_tuple(
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
other if expected.len() == 0 => {
|
||||
bail!("expected `unit` or 0-tuple found `{}`", desc(other))
|
||||
}
|
||||
other => bail!("expected `tuple` found `{}`", desc(other)),
|
||||
}
|
||||
}
|
||||
@@ -1419,7 +1412,10 @@ pub fn typecheck_record(
|
||||
pub fn typecheck_variant(
|
||||
ty: &InterfaceType,
|
||||
types: &ComponentTypes,
|
||||
expected: &[(&str, fn(&InterfaceType, &ComponentTypes) -> Result<()>)],
|
||||
expected: &[(
|
||||
&str,
|
||||
Option<fn(&InterfaceType, &ComponentTypes) -> Result<()>>,
|
||||
)],
|
||||
) -> Result<()> {
|
||||
match ty {
|
||||
InterfaceType::Variant(index) => {
|
||||
@@ -1434,11 +1430,20 @@ pub fn typecheck_variant(
|
||||
}
|
||||
|
||||
for (case, &(name, check)) in cases.iter().zip(expected) {
|
||||
check(&case.ty, types)
|
||||
.with_context(|| format!("type mismatch for case {}", name))?;
|
||||
|
||||
if case.name != name {
|
||||
bail!("expected variant case named {}, found {}", name, case.name);
|
||||
bail!("expected variant case named {name}, found {}", case.name);
|
||||
}
|
||||
|
||||
match (check, &case.ty) {
|
||||
(Some(check), Some(ty)) => check(ty, types)
|
||||
.with_context(|| format!("type mismatch for case {name}"))?,
|
||||
(None, None) => {}
|
||||
(Some(_), None) => {
|
||||
bail!("case `{name}` has no type but one was expected")
|
||||
}
|
||||
(None, Some(_)) => {
|
||||
bail!("case `{name}` has a type but none was expected")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1558,8 +1563,7 @@ where
|
||||
{
|
||||
type Lower = TupleLower2<<u32 as ComponentType>::Lower, T::Lower>;
|
||||
|
||||
const ABI: CanonicalAbiInfo =
|
||||
CanonicalAbiInfo::variant_static(&[<() as ComponentType>::ABI, T::ABI]);
|
||||
const ABI: CanonicalAbiInfo = CanonicalAbiInfo::variant_static(&[None, Some(T::ABI)]);
|
||||
|
||||
fn typecheck(ty: &InterfaceType, types: &ComponentTypes) -> Result<()> {
|
||||
match ty {
|
||||
@@ -1573,7 +1577,7 @@ unsafe impl<T> ComponentVariant for Option<T>
|
||||
where
|
||||
T: ComponentType,
|
||||
{
|
||||
const CASES: &'static [CanonicalAbiInfo] = &[<() as ComponentType>::ABI, T::ABI];
|
||||
const CASES: &'static [Option<CanonicalAbiInfo>] = &[None, Some(T::ABI)];
|
||||
}
|
||||
|
||||
unsafe impl<T> Lower for Option<T>
|
||||
@@ -1667,17 +1671,25 @@ where
|
||||
{
|
||||
type Lower = ResultLower<T::Lower, E::Lower>;
|
||||
|
||||
const ABI: CanonicalAbiInfo = CanonicalAbiInfo::variant_static(&[T::ABI, E::ABI]);
|
||||
const ABI: CanonicalAbiInfo = CanonicalAbiInfo::variant_static(&[Some(T::ABI), Some(E::ABI)]);
|
||||
|
||||
fn typecheck(ty: &InterfaceType, types: &ComponentTypes) -> Result<()> {
|
||||
match ty {
|
||||
InterfaceType::Expected(r) => {
|
||||
let expected = &types[*r];
|
||||
T::typecheck(&expected.ok, types)?;
|
||||
E::typecheck(&expected.err, types)?;
|
||||
InterfaceType::Result(r) => {
|
||||
let result = &types[*r];
|
||||
match &result.ok {
|
||||
Some(ty) => T::typecheck(ty, types)?,
|
||||
None if T::IS_RUST_UNIT_TYPE => {}
|
||||
None => bail!("expected no `ok` type"),
|
||||
}
|
||||
match &result.err {
|
||||
Some(ty) => E::typecheck(ty, types)?,
|
||||
None if E::IS_RUST_UNIT_TYPE => {}
|
||||
None => bail!("expected no `err` type"),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
other => bail!("expected `expected` found `{}`", desc(other)),
|
||||
other => bail!("expected `result` found `{}`", desc(other)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1715,7 +1727,7 @@ where
|
||||
T: ComponentType,
|
||||
E: ComponentType,
|
||||
{
|
||||
const CASES: &'static [CanonicalAbiInfo] = &[T::ABI, E::ABI];
|
||||
const CASES: &'static [Option<CanonicalAbiInfo>] = &[Some(T::ABI), Some(E::ABI)];
|
||||
}
|
||||
|
||||
unsafe impl<T, E> Lower for Result<T, E>
|
||||
@@ -1896,6 +1908,15 @@ macro_rules! impl_component_ty_for_tuples {
|
||||
$($t::ABI),*
|
||||
]);
|
||||
|
||||
const IS_RUST_UNIT_TYPE: bool = {
|
||||
let mut _is_unit = true;
|
||||
$(
|
||||
let _anything_to_bind_the_macro_variable = $t::IS_RUST_UNIT_TYPE;
|
||||
_is_unit = false;
|
||||
)*
|
||||
_is_unit
|
||||
};
|
||||
|
||||
fn typecheck(
|
||||
ty: &InterfaceType,
|
||||
types: &ComponentTypes,
|
||||
@@ -1944,19 +1965,19 @@ macro_rules! impl_component_ty_for_tuples {
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
unsafe impl<$($t,)*> ComponentParams for ($($t,)*)
|
||||
unsafe impl<$($t,)*> ComponentNamedList for ($($t,)*)
|
||||
where $($t: ComponentType),*
|
||||
{
|
||||
fn typecheck_params(
|
||||
params: &[(Option<String>, InterfaceType)],
|
||||
fn typecheck_named_list(
|
||||
names: &[(Option<String>, InterfaceType)],
|
||||
_types: &ComponentTypes,
|
||||
) -> Result<()> {
|
||||
if params.len() != $n {
|
||||
bail!("expected {} types, found {}", $n, params.len());
|
||||
if names.len() != $n {
|
||||
bail!("expected {} types, found {}", $n, names.len());
|
||||
}
|
||||
let mut params = params.iter().map(|i| &i.1);
|
||||
$($t::typecheck(params.next().unwrap(), _types)?;)*
|
||||
debug_assert!(params.next().is_none());
|
||||
let mut names = names.iter().map(|i| &i.1);
|
||||
$($t::typecheck(names.next().unwrap(), _types)?;)*
|
||||
debug_assert!(names.next().is_none());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1978,14 +1999,13 @@ fn desc(ty: &InterfaceType) -> &'static str {
|
||||
InterfaceType::S64 => "s64",
|
||||
InterfaceType::Float32 => "f32",
|
||||
InterfaceType::Float64 => "f64",
|
||||
InterfaceType::Unit => "unit",
|
||||
InterfaceType::Bool => "bool",
|
||||
InterfaceType::Char => "char",
|
||||
InterfaceType::String => "string",
|
||||
InterfaceType::List(_) => "list",
|
||||
InterfaceType::Tuple(_) => "tuple",
|
||||
InterfaceType::Option(_) => "option",
|
||||
InterfaceType::Expected(_) => "expected",
|
||||
InterfaceType::Result(_) => "result",
|
||||
|
||||
InterfaceType::Record(_) => "record",
|
||||
InterfaceType::Variant(_) => "variant",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::component::func::HostFunc;
|
||||
use crate::component::{Component, ComponentParams, Func, Lift, Lower, TypedFunc};
|
||||
use crate::component::{Component, ComponentNamedList, Func, Lift, Lower, TypedFunc};
|
||||
use crate::instance::OwnedImports;
|
||||
use crate::store::{StoreOpaque, Stored};
|
||||
use crate::{AsContextMut, Module, StoreContextMut};
|
||||
@@ -90,8 +90,8 @@ impl Instance {
|
||||
name: &str,
|
||||
) -> Result<TypedFunc<Params, Results>>
|
||||
where
|
||||
Params: ComponentParams + Lower,
|
||||
Results: Lift,
|
||||
Params: ComponentNamedList + Lower,
|
||||
Results: ComponentNamedList + Lift,
|
||||
S: AsContextMut,
|
||||
{
|
||||
let f = self
|
||||
@@ -585,8 +585,8 @@ impl<'a, 'store> ExportInstance<'a, 'store> {
|
||||
/// Same as [`Instance::get_typed_func`]
|
||||
pub fn typed_func<Params, Results>(&mut self, name: &str) -> Result<TypedFunc<Params, Results>>
|
||||
where
|
||||
Params: ComponentParams + Lower,
|
||||
Results: Lift,
|
||||
Params: ComponentNamedList + Lower,
|
||||
Results: ComponentNamedList + Lift,
|
||||
{
|
||||
let func = self
|
||||
.func(name)
|
||||
|
||||
@@ -238,7 +238,7 @@ impl<T> LinkerInstance<'_, T> {
|
||||
/// called, which must return a `Val` which is an instance of the result
|
||||
/// type of the import.
|
||||
pub fn func_new<
|
||||
F: Fn(StoreContextMut<'_, T>, &[Val]) -> Result<Val> + Send + Sync + 'static,
|
||||
F: Fn(StoreContextMut<'_, T>, &[Val], &mut [Val]) -> Result<()> + Send + Sync + 'static,
|
||||
>(
|
||||
&mut self,
|
||||
component: &Component,
|
||||
|
||||
@@ -14,7 +14,7 @@ pub mod types;
|
||||
mod values;
|
||||
pub use self::component::Component;
|
||||
pub use self::func::{
|
||||
ComponentParams, ComponentType, Func, IntoComponentFunc, Lift, Lower, TypedFunc, WasmList,
|
||||
ComponentNamedList, ComponentType, Func, IntoComponentFunc, Lift, Lower, TypedFunc, WasmList,
|
||||
WasmStr,
|
||||
};
|
||||
pub use self::instance::{ExportInstance, Exports, Instance, InstancePre};
|
||||
|
||||
@@ -7,8 +7,8 @@ use std::mem;
|
||||
use std::ops::Deref;
|
||||
use std::sync::Arc;
|
||||
use wasmtime_environ::component::{
|
||||
CanonicalAbiInfo, ComponentTypes, InterfaceType, TypeEnumIndex, TypeExpectedIndex,
|
||||
TypeFlagsIndex, TypeInterfaceIndex, TypeOptionIndex, TypeRecordIndex, TypeTupleIndex,
|
||||
CanonicalAbiInfo, ComponentTypes, InterfaceType, TypeEnumIndex, TypeFlagsIndex,
|
||||
TypeInterfaceIndex, TypeOptionIndex, TypeRecordIndex, TypeResultIndex, TypeTupleIndex,
|
||||
TypeUnionIndex, TypeVariantIndex, VariantInfo,
|
||||
};
|
||||
|
||||
@@ -111,8 +111,8 @@ impl Tuple {
|
||||
pub struct Case<'a> {
|
||||
/// The name of the case
|
||||
pub name: &'a str,
|
||||
/// The type of the case
|
||||
pub ty: Type,
|
||||
/// The optional payload type of the case
|
||||
pub ty: Option<Type>,
|
||||
}
|
||||
|
||||
/// A `variant` interface type
|
||||
@@ -121,7 +121,7 @@ pub struct Variant(Handle<TypeVariantIndex>);
|
||||
|
||||
impl Variant {
|
||||
/// Instantiate this type with the specified case `name` and `value`.
|
||||
pub fn new_val(&self, name: &str, value: Val) -> Result<Val> {
|
||||
pub fn new_val(&self, name: &str, value: Option<Val>) -> Result<Val> {
|
||||
Ok(Val::Variant(values::Variant::new(self, name, value)?))
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ impl Variant {
|
||||
pub fn cases(&self) -> impl ExactSizeIterator<Item = Case> {
|
||||
self.0.types[self.0.index].cases.iter().map(|case| Case {
|
||||
name: &case.name,
|
||||
ty: Type::from(&case.ty, &self.0.types),
|
||||
ty: case.ty.as_ref().map(|ty| Type::from(ty, &self.0.types)),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -198,12 +198,12 @@ impl Union {
|
||||
|
||||
/// An `option` interface type
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub struct Option(Handle<TypeOptionIndex>);
|
||||
pub struct OptionType(Handle<TypeOptionIndex>);
|
||||
|
||||
impl Option {
|
||||
impl OptionType {
|
||||
/// Instantiate this type with the specified `value`.
|
||||
pub fn new_val(&self, value: std::option::Option<Val>) -> Result<Val> {
|
||||
Ok(Val::Option(values::Option::new(self, value)?))
|
||||
pub fn new_val(&self, value: Option<Val>) -> Result<Val> {
|
||||
Ok(Val::Option(values::OptionVal::new(self, value)?))
|
||||
}
|
||||
|
||||
/// Retrieve the type parameter for this `option`.
|
||||
@@ -222,22 +222,28 @@ impl Option {
|
||||
|
||||
/// An `expected` interface type
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub struct Expected(Handle<TypeExpectedIndex>);
|
||||
pub struct ResultType(Handle<TypeResultIndex>);
|
||||
|
||||
impl Expected {
|
||||
impl ResultType {
|
||||
/// Instantiate this type with the specified `value`.
|
||||
pub fn new_val(&self, value: Result<Val, Val>) -> Result<Val> {
|
||||
Ok(Val::Expected(values::Expected::new(self, value)?))
|
||||
pub fn new_val(&self, value: Result<Option<Val>, Option<Val>>) -> Result<Val> {
|
||||
Ok(Val::Result(values::ResultVal::new(self, value)?))
|
||||
}
|
||||
|
||||
/// Retrieve the `ok` type parameter for this `option`.
|
||||
pub fn ok(&self) -> Type {
|
||||
Type::from(&self.0.types[self.0.index].ok, &self.0.types)
|
||||
pub fn ok(&self) -> Option<Type> {
|
||||
Some(Type::from(
|
||||
self.0.types[self.0.index].ok.as_ref()?,
|
||||
&self.0.types,
|
||||
))
|
||||
}
|
||||
|
||||
/// Retrieve the `err` type parameter for this `option`.
|
||||
pub fn err(&self) -> Type {
|
||||
Type::from(&self.0.types[self.0.index].err, &self.0.types)
|
||||
pub fn err(&self) -> Option<Type> {
|
||||
Some(Type::from(
|
||||
self.0.types[self.0.index].err.as_ref()?,
|
||||
&self.0.types,
|
||||
))
|
||||
}
|
||||
|
||||
pub(crate) fn variant_info(&self) -> &VariantInfo {
|
||||
@@ -274,52 +280,29 @@ impl Flags {
|
||||
|
||||
/// Represents a component model interface type
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
#[allow(missing_docs)]
|
||||
pub enum Type {
|
||||
/// Unit
|
||||
Unit,
|
||||
/// Boolean
|
||||
Bool,
|
||||
/// Signed 8-bit integer
|
||||
S8,
|
||||
/// Unsigned 8-bit integer
|
||||
U8,
|
||||
/// Signed 16-bit integer
|
||||
S16,
|
||||
/// Unsigned 16-bit integer
|
||||
U16,
|
||||
/// Signed 32-bit integer
|
||||
S32,
|
||||
/// Unsigned 32-bit integer
|
||||
U32,
|
||||
/// Signed 64-bit integer
|
||||
S64,
|
||||
/// Unsigned 64-bit integer
|
||||
U64,
|
||||
/// 64-bit floating point value
|
||||
Float32,
|
||||
/// 64-bit floating point value
|
||||
Float64,
|
||||
/// 32-bit character
|
||||
Char,
|
||||
/// Character string
|
||||
String,
|
||||
/// List of values
|
||||
List(List),
|
||||
/// Record
|
||||
Record(Record),
|
||||
/// Tuple
|
||||
Tuple(Tuple),
|
||||
/// Variant
|
||||
Variant(Variant),
|
||||
/// Enum
|
||||
Enum(Enum),
|
||||
/// Union
|
||||
Union(Union),
|
||||
/// Option
|
||||
Option(Option),
|
||||
/// Expected
|
||||
Expected(Expected),
|
||||
/// Bit flags
|
||||
Option(OptionType),
|
||||
Result(ResultType),
|
||||
Flags(Flags),
|
||||
}
|
||||
|
||||
@@ -402,12 +385,12 @@ impl Type {
|
||||
}
|
||||
}
|
||||
|
||||
/// Retrieve the inner [`Option`] of a [`Type::Option`].
|
||||
/// Retrieve the inner [`OptionType`] of a [`Type::Option`].
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This will panic if `self` is not a [`Type::Option`].
|
||||
pub fn unwrap_option(&self) -> &Option {
|
||||
pub fn unwrap_option(&self) -> &OptionType {
|
||||
if let Type::Option(handle) = self {
|
||||
&handle
|
||||
} else {
|
||||
@@ -415,16 +398,16 @@ impl Type {
|
||||
}
|
||||
}
|
||||
|
||||
/// Retrieve the inner [`Expected`] of a [`Type::Expected`].
|
||||
/// Retrieve the inner [`ResultType`] of a [`Type::Result`].
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This will panic if `self` is not a [`Type::Expected`].
|
||||
pub fn unwrap_expected(&self) -> &Expected {
|
||||
if let Type::Expected(handle) = self {
|
||||
/// This will panic if `self` is not a [`Type::Result`].
|
||||
pub fn unwrap_result(&self) -> &ResultType {
|
||||
if let Type::Result(handle) = self {
|
||||
&handle
|
||||
} else {
|
||||
panic!("attempted to unwrap a {} as a expected", self.desc())
|
||||
panic!("attempted to unwrap a {} as a result", self.desc())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -462,7 +445,6 @@ impl Type {
|
||||
/// Convert the specified `InterfaceType` to a `Type`.
|
||||
pub(crate) fn from(ty: &InterfaceType, types: &Arc<ComponentTypes>) -> Self {
|
||||
match ty {
|
||||
InterfaceType::Unit => Type::Unit,
|
||||
InterfaceType::Bool => Type::Bool,
|
||||
InterfaceType::S8 => Type::S8,
|
||||
InterfaceType::U8 => Type::U8,
|
||||
@@ -500,11 +482,11 @@ impl Type {
|
||||
index: *index,
|
||||
types: types.clone(),
|
||||
})),
|
||||
InterfaceType::Option(index) => Type::Option(Option(Handle {
|
||||
InterfaceType::Option(index) => Type::Option(OptionType(Handle {
|
||||
index: *index,
|
||||
types: types.clone(),
|
||||
})),
|
||||
InterfaceType::Expected(index) => Type::Expected(Expected(Handle {
|
||||
InterfaceType::Result(index) => Type::Result(ResultType(Handle {
|
||||
index: *index,
|
||||
types: types.clone(),
|
||||
})),
|
||||
@@ -517,7 +499,6 @@ impl Type {
|
||||
|
||||
fn desc(&self) -> &'static str {
|
||||
match self {
|
||||
Type::Unit => "unit",
|
||||
Type::Bool => "bool",
|
||||
Type::S8 => "s8",
|
||||
Type::U8 => "u8",
|
||||
@@ -538,7 +519,7 @@ impl Type {
|
||||
Type::Enum(_) => "enum",
|
||||
Type::Union(_) => "union",
|
||||
Type::Option(_) => "option",
|
||||
Type::Expected(_) => "expected",
|
||||
Type::Result(_) => "result",
|
||||
Type::Flags(_) => "flags",
|
||||
}
|
||||
}
|
||||
@@ -546,7 +527,6 @@ impl Type {
|
||||
/// Calculate the size and alignment requirements for the specified type.
|
||||
pub(crate) fn canonical_abi(&self) -> &CanonicalAbiInfo {
|
||||
match self {
|
||||
Type::Unit => &CanonicalAbiInfo::ZERO,
|
||||
Type::Bool | Type::S8 | Type::U8 => &CanonicalAbiInfo::SCALAR1,
|
||||
Type::S16 | Type::U16 => &CanonicalAbiInfo::SCALAR2,
|
||||
Type::S32 | Type::U32 | Type::Char | Type::Float32 => &CanonicalAbiInfo::SCALAR4,
|
||||
@@ -558,7 +538,7 @@ impl Type {
|
||||
Type::Enum(handle) => handle.canonical_abi(),
|
||||
Type::Union(handle) => handle.canonical_abi(),
|
||||
Type::Option(handle) => handle.canonical_abi(),
|
||||
Type::Expected(handle) => handle.canonical_abi(),
|
||||
Type::Result(handle) => handle.canonical_abi(),
|
||||
Type::Flags(handle) => handle.canonical_abi(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,12 +180,12 @@ impl fmt::Debug for Tuple {
|
||||
pub struct Variant {
|
||||
ty: types::Variant,
|
||||
discriminant: u32,
|
||||
value: Box<Val>,
|
||||
value: Option<Box<Val>>,
|
||||
}
|
||||
|
||||
impl Variant {
|
||||
/// Instantiate the specified type with the specified case `name` and `value`.
|
||||
pub fn new(ty: &types::Variant, name: &str, value: Val) -> Result<Self> {
|
||||
pub fn new(ty: &types::Variant, name: &str, value: Option<Val>) -> Result<Self> {
|
||||
let (discriminant, case_type) = ty
|
||||
.cases()
|
||||
.enumerate()
|
||||
@@ -198,14 +198,12 @@ impl Variant {
|
||||
})
|
||||
.ok_or_else(|| anyhow!("unknown variant case: {name}"))?;
|
||||
|
||||
case_type
|
||||
.check(&value)
|
||||
.with_context(|| format!("type mismatch for case {name} of variant"))?;
|
||||
typecheck_payload(name, case_type.as_ref(), value.as_ref())?;
|
||||
|
||||
Ok(Self {
|
||||
ty: ty.clone(),
|
||||
discriminant: u32::try_from(discriminant)?,
|
||||
value: Box::new(value),
|
||||
value: value.map(Box::new),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -224,15 +222,26 @@ impl Variant {
|
||||
}
|
||||
|
||||
/// Returns the payload value for this variant.
|
||||
pub fn payload(&self) -> &Val {
|
||||
&self.value
|
||||
pub fn payload(&self) -> Option<&Val> {
|
||||
self.value.as_deref()
|
||||
}
|
||||
}
|
||||
|
||||
fn typecheck_payload(name: &str, case_type: Option<&Type>, value: Option<&Val>) -> Result<()> {
|
||||
match (case_type, value) {
|
||||
(Some(expected), Some(actual)) => expected
|
||||
.check(&actual)
|
||||
.with_context(|| format!("type mismatch for case {name} of variant")),
|
||||
(None, None) => Ok(()),
|
||||
(Some(_), None) => bail!("expected a payload for case `{name}`"),
|
||||
(None, Some(_)) => bail!("did not expect payload for case `{name}`"),
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Variant {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_tuple(self.discriminant())
|
||||
.field(self.payload())
|
||||
.field(&self.payload())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
@@ -279,7 +288,7 @@ impl fmt::Debug for Enum {
|
||||
pub struct Union {
|
||||
ty: types::Union,
|
||||
discriminant: u32,
|
||||
value: Box<Val>,
|
||||
value: Option<Box<Val>>,
|
||||
}
|
||||
|
||||
impl Union {
|
||||
@@ -293,7 +302,7 @@ impl Union {
|
||||
Ok(Self {
|
||||
ty: ty.clone(),
|
||||
discriminant,
|
||||
value: Box::new(value),
|
||||
value: Some(Box::new(value)),
|
||||
})
|
||||
} else {
|
||||
Err(anyhow!(
|
||||
@@ -315,7 +324,7 @@ impl Union {
|
||||
|
||||
/// Returns the payload value for this union.
|
||||
pub fn payload(&self) -> &Val {
|
||||
&self.value
|
||||
self.value.as_ref().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -328,15 +337,15 @@ impl fmt::Debug for Union {
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Clone)]
|
||||
pub struct Option {
|
||||
ty: types::Option,
|
||||
pub struct OptionVal {
|
||||
ty: types::OptionType,
|
||||
discriminant: u32,
|
||||
value: Box<Val>,
|
||||
value: Option<Box<Val>>,
|
||||
}
|
||||
|
||||
impl Option {
|
||||
impl OptionVal {
|
||||
/// Instantiate the specified type with the specified `value`.
|
||||
pub fn new(ty: &types::Option, value: std::option::Option<Val>) -> Result<Self> {
|
||||
pub fn new(ty: &types::OptionType, value: Option<Val>) -> Result<Self> {
|
||||
let value = value
|
||||
.map(|value| {
|
||||
ty.ty().check(&value).context("type mismatch for option")?;
|
||||
@@ -348,77 +357,69 @@ impl Option {
|
||||
Ok(Self {
|
||||
ty: ty.clone(),
|
||||
discriminant: if value.is_none() { 0 } else { 1 },
|
||||
value: Box::new(value.unwrap_or(Val::Unit)),
|
||||
value: value.map(Box::new),
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the type of this value.
|
||||
pub fn ty(&self) -> &types::Option {
|
||||
pub fn ty(&self) -> &types::OptionType {
|
||||
&self.ty
|
||||
}
|
||||
|
||||
/// Returns the optional value contained within.
|
||||
pub fn value(&self) -> std::option::Option<&Val> {
|
||||
if self.discriminant == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(&self.value)
|
||||
}
|
||||
pub fn value(&self) -> Option<&Val> {
|
||||
self.value.as_deref()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Option {
|
||||
impl fmt::Debug for OptionVal {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.value().fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Clone)]
|
||||
pub struct Expected {
|
||||
ty: types::Expected,
|
||||
pub struct ResultVal {
|
||||
ty: types::ResultType,
|
||||
discriminant: u32,
|
||||
value: Box<Val>,
|
||||
value: Option<Box<Val>>,
|
||||
}
|
||||
|
||||
impl Expected {
|
||||
impl ResultVal {
|
||||
/// Instantiate the specified type with the specified `value`.
|
||||
pub fn new(ty: &types::Expected, value: Result<Val, Val>) -> Result<Self> {
|
||||
pub fn new(ty: &types::ResultType, value: Result<Option<Val>, Option<Val>>) -> Result<Self> {
|
||||
Ok(Self {
|
||||
ty: ty.clone(),
|
||||
discriminant: if value.is_ok() { 0 } else { 1 },
|
||||
value: Box::new(match value {
|
||||
value: match value {
|
||||
Ok(value) => {
|
||||
ty.ok()
|
||||
.check(&value)
|
||||
.context("type mismatch for ok case of expected")?;
|
||||
value
|
||||
typecheck_payload("ok", ty.ok().as_ref(), value.as_ref())?;
|
||||
value.map(Box::new)
|
||||
}
|
||||
Err(value) => {
|
||||
ty.err()
|
||||
.check(&value)
|
||||
.context("type mismatch for err case of expected")?;
|
||||
value
|
||||
typecheck_payload("err", ty.err().as_ref(), value.as_ref())?;
|
||||
value.map(Box::new)
|
||||
}
|
||||
}),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the type of this value.
|
||||
pub fn ty(&self) -> &types::Expected {
|
||||
pub fn ty(&self) -> &types::ResultType {
|
||||
&self.ty
|
||||
}
|
||||
|
||||
/// Returns the result value contained within.
|
||||
pub fn value(&self) -> Result<&Val, &Val> {
|
||||
pub fn value(&self) -> Result<Option<&Val>, Option<&Val>> {
|
||||
if self.discriminant == 0 {
|
||||
Ok(&self.value)
|
||||
Ok(self.value.as_deref())
|
||||
} else {
|
||||
Err(&self.value)
|
||||
Err(self.value.as_deref())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Expected {
|
||||
impl fmt::Debug for ResultVal {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.value().fmt(f)
|
||||
}
|
||||
@@ -487,52 +488,29 @@ impl fmt::Debug for Flags {
|
||||
|
||||
/// Represents possible runtime values which a component function can either consume or produce
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
#[allow(missing_docs)]
|
||||
pub enum Val {
|
||||
/// Unit
|
||||
Unit,
|
||||
/// Boolean
|
||||
Bool(bool),
|
||||
/// Signed 8-bit integer
|
||||
S8(i8),
|
||||
/// Unsigned 8-bit integer
|
||||
U8(u8),
|
||||
/// Signed 16-bit integer
|
||||
S16(i16),
|
||||
/// Unsigned 16-bit integer
|
||||
U16(u16),
|
||||
/// Signed 32-bit integer
|
||||
S32(i32),
|
||||
/// Unsigned 32-bit integer
|
||||
U32(u32),
|
||||
/// Signed 64-bit integer
|
||||
S64(i64),
|
||||
/// Unsigned 64-bit integer
|
||||
U64(u64),
|
||||
/// 32-bit floating point value
|
||||
Float32(u32),
|
||||
/// 64-bit floating point value
|
||||
Float64(u64),
|
||||
/// 32-bit character
|
||||
Char(char),
|
||||
/// Character string
|
||||
String(Box<str>),
|
||||
/// List of values
|
||||
List(List),
|
||||
/// Record
|
||||
Record(Record),
|
||||
/// Tuple
|
||||
Tuple(Tuple),
|
||||
/// Variant
|
||||
Variant(Variant),
|
||||
/// Enum
|
||||
Enum(Enum),
|
||||
/// Union
|
||||
Union(Union),
|
||||
/// Option
|
||||
Option(Option),
|
||||
/// Expected
|
||||
Expected(Expected),
|
||||
/// Bit flags
|
||||
Option(OptionVal),
|
||||
Result(ResultVal),
|
||||
Flags(Flags),
|
||||
}
|
||||
|
||||
@@ -540,7 +518,6 @@ impl Val {
|
||||
/// Retrieve the [`Type`] of this value.
|
||||
pub fn ty(&self) -> Type {
|
||||
match self {
|
||||
Val::Unit => Type::Unit,
|
||||
Val::Bool(_) => Type::Bool,
|
||||
Val::S8(_) => Type::S8,
|
||||
Val::U8(_) => Type::U8,
|
||||
@@ -560,8 +537,8 @@ impl Val {
|
||||
Val::Variant(Variant { ty, .. }) => Type::Variant(ty.clone()),
|
||||
Val::Enum(Enum { ty, .. }) => Type::Enum(ty.clone()),
|
||||
Val::Union(Union { ty, .. }) => Type::Union(ty.clone()),
|
||||
Val::Option(Option { ty, .. }) => Type::Option(ty.clone()),
|
||||
Val::Expected(Expected { ty, .. }) => Type::Expected(ty.clone()),
|
||||
Val::Option(OptionVal { ty, .. }) => Type::Option(ty.clone()),
|
||||
Val::Result(ResultVal { ty, .. }) => Type::Result(ty.clone()),
|
||||
Val::Flags(Flags { ty, .. }) => Type::Flags(ty.clone()),
|
||||
}
|
||||
}
|
||||
@@ -574,7 +551,6 @@ impl Val {
|
||||
src: &mut std::slice::Iter<'_, ValRaw>,
|
||||
) -> Result<Val> {
|
||||
Ok(match ty {
|
||||
Type::Unit => Val::Unit,
|
||||
Type::Bool => Val::Bool(bool::lift(store, options, next(src))?),
|
||||
Type::S8 => Val::S8(i8::lift(store, options, next(src))?),
|
||||
Type::U8 => Val::U8(u8::lift(store, options, next(src))?),
|
||||
@@ -622,13 +598,13 @@ impl Val {
|
||||
Val::Variant(Variant {
|
||||
ty: handle.clone(),
|
||||
discriminant,
|
||||
value: Box::new(value),
|
||||
value,
|
||||
})
|
||||
}
|
||||
Type::Enum(handle) => {
|
||||
let (discriminant, _) = lift_variant(
|
||||
handle.canonical_abi().flat_count(usize::MAX).unwrap(),
|
||||
handle.names().map(|_| Type::Unit),
|
||||
handle.names().map(|_| None),
|
||||
store,
|
||||
options,
|
||||
src,
|
||||
@@ -642,7 +618,7 @@ impl Val {
|
||||
Type::Union(handle) => {
|
||||
let (discriminant, value) = lift_variant(
|
||||
handle.canonical_abi().flat_count(usize::MAX).unwrap(),
|
||||
handle.types(),
|
||||
handle.types().map(Some),
|
||||
store,
|
||||
options,
|
||||
src,
|
||||
@@ -651,25 +627,25 @@ impl Val {
|
||||
Val::Union(Union {
|
||||
ty: handle.clone(),
|
||||
discriminant,
|
||||
value: Box::new(value),
|
||||
value,
|
||||
})
|
||||
}
|
||||
Type::Option(handle) => {
|
||||
let (discriminant, value) = lift_variant(
|
||||
handle.canonical_abi().flat_count(usize::MAX).unwrap(),
|
||||
[Type::Unit, handle.ty()].into_iter(),
|
||||
[None, Some(handle.ty())].into_iter(),
|
||||
store,
|
||||
options,
|
||||
src,
|
||||
)?;
|
||||
|
||||
Val::Option(Option {
|
||||
Val::Option(OptionVal {
|
||||
ty: handle.clone(),
|
||||
discriminant,
|
||||
value: Box::new(value),
|
||||
value,
|
||||
})
|
||||
}
|
||||
Type::Expected(handle) => {
|
||||
Type::Result(handle) => {
|
||||
let (discriminant, value) = lift_variant(
|
||||
handle.canonical_abi().flat_count(usize::MAX).unwrap(),
|
||||
[handle.ok(), handle.err()].into_iter(),
|
||||
@@ -678,10 +654,10 @@ impl Val {
|
||||
src,
|
||||
)?;
|
||||
|
||||
Val::Expected(Expected {
|
||||
Val::Result(ResultVal {
|
||||
ty: handle.clone(),
|
||||
discriminant,
|
||||
value: Box::new(value),
|
||||
value,
|
||||
})
|
||||
}
|
||||
Type::Flags(handle) => {
|
||||
@@ -703,7 +679,6 @@ impl Val {
|
||||
/// Deserialize a value of this type from the heap.
|
||||
pub(crate) fn load(ty: &Type, mem: &Memory, bytes: &[u8]) -> Result<Val> {
|
||||
Ok(match ty {
|
||||
Type::Unit => Val::Unit,
|
||||
Type::Bool => Val::Bool(bool::load(mem, bytes)?),
|
||||
Type::S8 => Val::S8(i8::load(mem, bytes)?),
|
||||
Type::U8 => Val::U8(u8::load(mem, bytes)?),
|
||||
@@ -742,13 +717,13 @@ impl Val {
|
||||
Val::Variant(Variant {
|
||||
ty: handle.clone(),
|
||||
discriminant,
|
||||
value: Box::new(value),
|
||||
value,
|
||||
})
|
||||
}
|
||||
Type::Enum(handle) => {
|
||||
let (discriminant, _) = load_variant(
|
||||
handle.variant_info(),
|
||||
handle.names().map(|_| Type::Unit),
|
||||
handle.names().map(|_| None),
|
||||
mem,
|
||||
bytes,
|
||||
)?;
|
||||
@@ -760,29 +735,29 @@ impl Val {
|
||||
}
|
||||
Type::Union(handle) => {
|
||||
let (discriminant, value) =
|
||||
load_variant(handle.variant_info(), handle.types(), mem, bytes)?;
|
||||
load_variant(handle.variant_info(), handle.types().map(Some), mem, bytes)?;
|
||||
|
||||
Val::Union(Union {
|
||||
ty: handle.clone(),
|
||||
discriminant,
|
||||
value: Box::new(value),
|
||||
value,
|
||||
})
|
||||
}
|
||||
Type::Option(handle) => {
|
||||
let (discriminant, value) = load_variant(
|
||||
handle.variant_info(),
|
||||
[Type::Unit, handle.ty()].into_iter(),
|
||||
[None, Some(handle.ty())].into_iter(),
|
||||
mem,
|
||||
bytes,
|
||||
)?;
|
||||
|
||||
Val::Option(Option {
|
||||
Val::Option(OptionVal {
|
||||
ty: handle.clone(),
|
||||
discriminant,
|
||||
value: Box::new(value),
|
||||
value,
|
||||
})
|
||||
}
|
||||
Type::Expected(handle) => {
|
||||
Type::Result(handle) => {
|
||||
let (discriminant, value) = load_variant(
|
||||
handle.variant_info(),
|
||||
[handle.ok(), handle.err()].into_iter(),
|
||||
@@ -790,10 +765,10 @@ impl Val {
|
||||
bytes,
|
||||
)?;
|
||||
|
||||
Val::Expected(Expected {
|
||||
Val::Result(ResultVal {
|
||||
ty: handle.clone(),
|
||||
discriminant,
|
||||
value: Box::new(value),
|
||||
value,
|
||||
})
|
||||
}
|
||||
Type::Flags(handle) => Val::Flags(Flags {
|
||||
@@ -819,7 +794,6 @@ impl Val {
|
||||
dst: &mut std::slice::IterMut<'_, MaybeUninit<ValRaw>>,
|
||||
) -> Result<()> {
|
||||
match self {
|
||||
Val::Unit => (),
|
||||
Val::Bool(value) => value.lower(store, options, next_mut(dst))?,
|
||||
Val::S8(value) => value.lower(store, options, next_mut(dst))?,
|
||||
Val::U8(value) => value.lower(store, options, next_mut(dst))?,
|
||||
@@ -863,23 +837,28 @@ impl Val {
|
||||
value,
|
||||
..
|
||||
})
|
||||
| Val::Option(Option {
|
||||
| Val::Option(OptionVal {
|
||||
discriminant,
|
||||
value,
|
||||
..
|
||||
})
|
||||
| Val::Expected(Expected {
|
||||
| Val::Result(ResultVal {
|
||||
discriminant,
|
||||
value,
|
||||
..
|
||||
}) => {
|
||||
next_mut(dst).write(ValRaw::u32(*discriminant));
|
||||
value.lower(store, options, dst)?;
|
||||
|
||||
// For the remaining lowered representation of this variant that
|
||||
// the payload didn't write we write out zeros here to ensure
|
||||
// the entire variant is written.
|
||||
let value_flat = value.ty().canonical_abi().flat_count(usize::MAX).unwrap();
|
||||
let value_flat = match value {
|
||||
Some(value) => {
|
||||
value.lower(store, options, dst)?;
|
||||
value.ty().canonical_abi().flat_count(usize::MAX).unwrap()
|
||||
}
|
||||
None => 0,
|
||||
};
|
||||
let variant_flat = self.ty().canonical_abi().flat_count(usize::MAX).unwrap();
|
||||
for _ in (1 + value_flat)..variant_flat {
|
||||
next_mut(dst).write(ValRaw::u64(0));
|
||||
@@ -903,7 +882,6 @@ impl Val {
|
||||
debug_assert!(offset % usize::try_from(self.ty().canonical_abi().align32)? == 0);
|
||||
|
||||
match self {
|
||||
Val::Unit => (),
|
||||
Val::Bool(value) => value.store(mem, offset)?,
|
||||
Val::S8(value) => value.store(mem, offset)?,
|
||||
Val::U8(value) => value.store(mem, offset)?,
|
||||
@@ -936,29 +914,53 @@ impl Val {
|
||||
discriminant,
|
||||
value,
|
||||
ty,
|
||||
}) => self.store_variant(*discriminant, value, ty.variant_info(), mem, offset)?,
|
||||
}) => self.store_variant(
|
||||
*discriminant,
|
||||
value.as_deref(),
|
||||
ty.variant_info(),
|
||||
mem,
|
||||
offset,
|
||||
)?,
|
||||
|
||||
Val::Enum(Enum { discriminant, ty }) => {
|
||||
self.store_variant(*discriminant, &Val::Unit, ty.variant_info(), mem, offset)?
|
||||
self.store_variant(*discriminant, None, ty.variant_info(), mem, offset)?
|
||||
}
|
||||
|
||||
Val::Union(Union {
|
||||
discriminant,
|
||||
value,
|
||||
ty,
|
||||
}) => self.store_variant(*discriminant, value, ty.variant_info(), mem, offset)?,
|
||||
}) => self.store_variant(
|
||||
*discriminant,
|
||||
value.as_deref(),
|
||||
ty.variant_info(),
|
||||
mem,
|
||||
offset,
|
||||
)?,
|
||||
|
||||
Val::Option(Option {
|
||||
Val::Option(OptionVal {
|
||||
discriminant,
|
||||
value,
|
||||
ty,
|
||||
}) => self.store_variant(*discriminant, value, ty.variant_info(), mem, offset)?,
|
||||
}) => self.store_variant(
|
||||
*discriminant,
|
||||
value.as_deref(),
|
||||
ty.variant_info(),
|
||||
mem,
|
||||
offset,
|
||||
)?,
|
||||
|
||||
Val::Expected(Expected {
|
||||
Val::Result(ResultVal {
|
||||
discriminant,
|
||||
value,
|
||||
ty,
|
||||
}) => self.store_variant(*discriminant, value, ty.variant_info(), mem, offset)?,
|
||||
}) => self.store_variant(
|
||||
*discriminant,
|
||||
value.as_deref(),
|
||||
ty.variant_info(),
|
||||
mem,
|
||||
offset,
|
||||
)?,
|
||||
|
||||
Val::Flags(Flags { count, value, .. }) => {
|
||||
match FlagsSize::from_count(*count as usize) {
|
||||
@@ -982,7 +984,7 @@ impl Val {
|
||||
fn store_variant<T>(
|
||||
&self,
|
||||
discriminant: u32,
|
||||
value: &Val,
|
||||
value: Option<&Val>,
|
||||
info: &VariantInfo,
|
||||
mem: &mut MemoryMut<'_, T>,
|
||||
offset: usize,
|
||||
@@ -993,8 +995,12 @@ impl Val {
|
||||
DiscriminantSize::Size4 => discriminant.store(mem, offset)?,
|
||||
}
|
||||
|
||||
let offset = offset + usize::try_from(info.payload_offset32).unwrap();
|
||||
value.store(mem, offset)
|
||||
if let Some(value) = value {
|
||||
let offset = offset + usize::try_from(info.payload_offset32).unwrap();
|
||||
value.store(mem, offset)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1048,10 +1054,10 @@ fn load_record(
|
||||
|
||||
fn load_variant(
|
||||
info: &VariantInfo,
|
||||
mut types: impl ExactSizeIterator<Item = Type>,
|
||||
mut types: impl ExactSizeIterator<Item = Option<Type>>,
|
||||
mem: &Memory,
|
||||
bytes: &[u8],
|
||||
) -> Result<(u32, Val)> {
|
||||
) -> Result<(u32, Option<Box<Val>>)> {
|
||||
let discriminant = match info.size {
|
||||
DiscriminantSize::Size1 => u32::from(u8::load(mem, &bytes[..1])?),
|
||||
DiscriminantSize::Size2 => u32::from(u16::load(mem, &bytes[..2])?),
|
||||
@@ -1064,26 +1070,40 @@ fn load_variant(
|
||||
types.len()
|
||||
)
|
||||
})?;
|
||||
let payload_offset = usize::try_from(info.payload_offset32).unwrap();
|
||||
let case_size = usize::try_from(case_ty.canonical_abi().size32).unwrap();
|
||||
let value = Val::load(&case_ty, mem, &bytes[payload_offset..][..case_size])?;
|
||||
let value = match case_ty {
|
||||
Some(case_ty) => {
|
||||
let payload_offset = usize::try_from(info.payload_offset32).unwrap();
|
||||
let case_size = usize::try_from(case_ty.canonical_abi().size32).unwrap();
|
||||
Some(Box::new(Val::load(
|
||||
&case_ty,
|
||||
mem,
|
||||
&bytes[payload_offset..][..case_size],
|
||||
)?))
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
Ok((discriminant, value))
|
||||
}
|
||||
|
||||
fn lift_variant<'a>(
|
||||
flatten_count: usize,
|
||||
mut types: impl ExactSizeIterator<Item = Type>,
|
||||
mut types: impl ExactSizeIterator<Item = Option<Type>>,
|
||||
store: &StoreOpaque,
|
||||
options: &Options,
|
||||
src: &mut std::slice::Iter<'_, ValRaw>,
|
||||
) -> Result<(u32, Val)> {
|
||||
) -> Result<(u32, Option<Box<Val>>)> {
|
||||
let len = types.len();
|
||||
let discriminant = next(src).get_u32();
|
||||
let ty = types
|
||||
.nth(discriminant as usize)
|
||||
.ok_or_else(|| anyhow!("discriminant {} out of range [0..{})", discriminant, len))?;
|
||||
let value = Val::lift(&ty, store, options, src)?;
|
||||
let value_flat = ty.canonical_abi().flat_count(usize::MAX).unwrap();
|
||||
let (value, value_flat) = match ty {
|
||||
Some(ty) => (
|
||||
Some(Box::new(Val::lift(&ty, store, options, src)?)),
|
||||
ty.canonical_abi().flat_count(usize::MAX).unwrap(),
|
||||
),
|
||||
None => (None, 0),
|
||||
};
|
||||
for _ in (1 + value_flat)..flatten_count {
|
||||
next(src);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user