Refactor the ComponentValue impls for tuples (#4217)
These helper functions are also useful for implementing this trait on user-defined record and tuple types.
This commit is contained in:
@@ -1433,6 +1433,7 @@ unsafe impl<T: ComponentValue> ComponentValue for WasmList<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Round `a` up to the next multiple of `align`, assuming that `align` is a power of 2.
|
||||||
#[inline]
|
#[inline]
|
||||||
const fn align_to(a: usize, align: u32) -> usize {
|
const fn align_to(a: usize, align: u32) -> usize {
|
||||||
debug_assert!(align.is_power_of_two());
|
debug_assert!(align.is_power_of_two());
|
||||||
@@ -1440,6 +1441,43 @@ const fn align_to(a: usize, align: u32) -> usize {
|
|||||||
(a + (align - 1)) & !(align - 1)
|
(a + (align - 1)) & !(align - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// For a field of type T starting after `offset` bytes, updates the offset to reflect the correct
|
||||||
|
/// alignment and size of T. Returns the correctly aligned offset for the start of the field.
|
||||||
|
#[inline]
|
||||||
|
pub fn next_field<T: ComponentValue>(offset: &mut usize) -> usize {
|
||||||
|
*offset = align_to(*offset, T::align());
|
||||||
|
let result = *offset;
|
||||||
|
*offset += T::size();
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Verify that the given wasm type is a tuple with the expected fields in the right order.
|
||||||
|
#[inline]
|
||||||
|
fn typecheck_tuple(
|
||||||
|
ty: &InterfaceType,
|
||||||
|
types: &ComponentTypes,
|
||||||
|
op: Op,
|
||||||
|
expected: &[fn(&InterfaceType, &ComponentTypes, Op) -> Result<()>],
|
||||||
|
) -> Result<()> {
|
||||||
|
match ty {
|
||||||
|
InterfaceType::Tuple(t) => {
|
||||||
|
let tuple = &types[*t];
|
||||||
|
if tuple.types.len() != expected.len() {
|
||||||
|
bail!(
|
||||||
|
"expected {}-tuple, found {}-tuple",
|
||||||
|
expected.len(),
|
||||||
|
tuple.types.len()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
for (ty, check) in tuple.types.iter().zip(expected) {
|
||||||
|
check(ty, types, op)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
other => bail!("expected `tuple` found `{}`", desc(other)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
unsafe impl<T> ComponentValue for Option<T>
|
unsafe impl<T> ComponentValue for Option<T>
|
||||||
where
|
where
|
||||||
T: ComponentValue,
|
T: ComponentValue,
|
||||||
@@ -1683,19 +1721,7 @@ macro_rules! impl_component_ty_for_tuples {
|
|||||||
types: &ComponentTypes,
|
types: &ComponentTypes,
|
||||||
op: Op,
|
op: Op,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
match ty {
|
typecheck_tuple(ty, types, op, &[$($t::typecheck),*])
|
||||||
InterfaceType::Tuple(t) => {
|
|
||||||
let tuple = &types[*t];
|
|
||||||
if tuple.types.len() != $n {
|
|
||||||
bail!("expected {}-tuple, found {}-tuple", $n, tuple.types.len());
|
|
||||||
}
|
|
||||||
let mut tuple = tuple.types.iter();
|
|
||||||
$($t::typecheck(tuple.next().unwrap(), types, op)?;)*
|
|
||||||
debug_assert!(tuple.next().is_none());
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
other => bail!("expected `tuple` found `{}`", desc(other)),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower<U>(
|
fn lower<U>(
|
||||||
@@ -1712,7 +1738,7 @@ macro_rules! impl_component_ty_for_tuples {
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn size() -> usize {
|
fn size() -> usize {
|
||||||
let mut size = 0;
|
let mut size = 0;
|
||||||
$(size = align_to(size, $t::align()) + $t::size();)*
|
$(next_field::<$t>(&mut size);)*
|
||||||
size
|
size
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1727,12 +1753,7 @@ macro_rules! impl_component_ty_for_tuples {
|
|||||||
let ($($t,)*) = self;
|
let ($($t,)*) = self;
|
||||||
// TODO: this requires that `offset` is aligned which we may not
|
// TODO: this requires that `offset` is aligned which we may not
|
||||||
// want to do
|
// want to do
|
||||||
$(
|
$($t.store(memory, next_field::<$t>(&mut offset))?;)*
|
||||||
offset = align_to(offset, $t::align());
|
|
||||||
$t.store(memory, offset)?;
|
|
||||||
offset += $t::size();
|
|
||||||
)*
|
|
||||||
drop(offset); // silence warning about last assignment
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1741,12 +1762,8 @@ macro_rules! impl_component_ty_for_tuples {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn load(memory: &Memory<'_>, bytes: &[u8]) -> Result<Self> {
|
fn load(memory: &Memory<'_>, bytes: &[u8]) -> Result<Self> {
|
||||||
let mut _offset = 0;
|
let mut offset = 0;
|
||||||
$(
|
$(let $t = $t::load(memory, &bytes[next_field::<$t>(&mut offset)..][..$t::size()])?;)*
|
||||||
_offset = align_to(_offset, $t::align());
|
|
||||||
let $t = $t::load(memory, &bytes[_offset..][..$t::size()])?;
|
|
||||||
_offset += $t::size();
|
|
||||||
)*
|
|
||||||
Ok(($($t,)*))
|
Ok(($($t,)*))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user