use std::ops::Add;
use frunk::HList;
use super::result_storage::ResultStorage;
use crate::{
memory_layout::FlatLayout, primitive_types::FlatType, util::Split, GuestPointer,
InstanceWithMemory, Layout, Memory, Runtime, RuntimeError, RuntimeMemory, WitLoad,
};
pub trait GuestInterface {
type FlatHostParameters: FlatLayout;
type FlatGuestParameters: FlatLayout;
type ResultStorage: ResultStorage;
fn lift_parameters<Instance, HostParameters>(
guest_parameters: Self::FlatGuestParameters,
memory: &Memory<'_, Instance>,
) -> Result<(HostParameters, Self::ResultStorage), RuntimeError>
where
HostParameters: WitLoad,
HostParameters::Layout: Layout<Flat = Self::FlatHostParameters>,
Instance: InstanceWithMemory,
<Instance::Runtime as Runtime>::Memory: RuntimeMemory<Instance>;
}
macro_rules! direct_interface {
($( $types:ident ),* $(,)*) => {
direct_interface_with_result!($( $types ),* =>);
direct_interface_with_result!($( $types ),* => FlatResult);
};
}
macro_rules! direct_interface_with_result {
($( $types:ident ),* => $( $flat_result:ident )?) => {
impl<$( $types, )* $( $flat_result )*> GuestInterface
for (HList![$( $types, )*], HList![$( $flat_result )*])
where
HList![$( $types, )*]: FlatLayout,
$( $flat_result: FlatType, )*
{
type FlatHostParameters = HList![$( $types, )*];
type FlatGuestParameters = HList![$( $types, )*];
type ResultStorage = ();
fn lift_parameters<Instance, HostParameters>(
guest_parameters: Self::FlatGuestParameters,
memory: &Memory<'_, Instance>,
) -> Result<(HostParameters, Self::ResultStorage), RuntimeError>
where
HostParameters: WitLoad,
HostParameters::Layout: Layout<Flat = Self::FlatHostParameters>,
Instance: InstanceWithMemory,
<Instance::Runtime as Runtime>::Memory: RuntimeMemory<Instance>,
{
let parameters = HostParameters::lift_from(guest_parameters, memory)?;
Ok((parameters, ()))
}
}
};
}
repeat_macro!(direct_interface => A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
macro_rules! indirect_results {
($( $types:ident ),*) => {
impl<$( $types, )* Y, Z, Tail> GuestInterface
for (HList![$( $types, )*], HList![Y, Z, ...Tail])
where
HList![$( $types, )*]: FlatLayout + Add<HList![i32]>,
<HList![$( $types, )*] as Add<HList![i32]>>::Output:
FlatLayout + Split<HList![$( $types, )*], Remainder = HList![i32]>,
{
type FlatHostParameters = HList![$( $types, )*];
type FlatGuestParameters = <Self::FlatHostParameters as Add<HList![i32]>>::Output;
type ResultStorage = GuestPointer;
fn lift_parameters<Instance, Parameters>(
guest_parameters: Self::FlatGuestParameters,
memory: &Memory<'_, Instance>,
) -> Result<(Parameters, Self::ResultStorage), RuntimeError>
where
Parameters: WitLoad,
Parameters::Layout: Layout<Flat = Self::FlatHostParameters>,
Instance: InstanceWithMemory,
<Instance::Runtime as Runtime>::Memory: RuntimeMemory<Instance>,
{
let (parameters_layout, result_storage_layout) = guest_parameters.split();
let parameters = Parameters::lift_from(parameters_layout, memory)?;
let result_storage = Self::ResultStorage::lift_from(result_storage_layout, memory)?;
Ok((parameters, result_storage))
}
}
};
}
repeat_macro!(indirect_results => A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
macro_rules! indirect_parameters {
(=> $( $flat_result:ident )? ) => {
impl<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, Tail $(, $flat_result )*>
GuestInterface
for (
HList![A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, ...Tail],
HList![$( $flat_result )*],
)
where
HList![A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, ...Tail]: FlatLayout,
$( $flat_result: FlatType, )*
{
type FlatHostParameters =
HList![A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, ...Tail];
type FlatGuestParameters = HList![i32];
type ResultStorage = ();
fn lift_parameters<Instance, Parameters>(
guest_parameters: Self::FlatGuestParameters,
memory: &Memory<'_, Instance>,
) -> Result<(Parameters, Self::ResultStorage), RuntimeError>
where
Parameters: WitLoad,
Parameters::Layout: Layout<Flat = Self::FlatHostParameters>,
Instance: InstanceWithMemory,
<Instance::Runtime as Runtime>::Memory: RuntimeMemory<Instance>,
{
let parameters_location = GuestPointer::lift_from(guest_parameters, memory)?;
let parameters = Parameters::load(memory, parameters_location)?;
Ok((parameters, ()))
}
}
};
}
indirect_parameters!(=>);
indirect_parameters!(=> Z);
impl<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, OtherParameters, Y, Z, OtherResults>
GuestInterface
for (
HList![A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, ...OtherParameters],
HList![Y, Z, ...OtherResults],
)
where
HList![A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, ...OtherParameters]: FlatLayout,
HList![Y, Z, ...OtherResults]: FlatLayout,
{
type FlatHostParameters =
HList![A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, ...OtherParameters];
type FlatGuestParameters = HList![i32, i32];
type ResultStorage = GuestPointer;
fn lift_parameters<Instance, Parameters>(
guest_parameters: Self::FlatGuestParameters,
memory: &Memory<'_, Instance>,
) -> Result<(Parameters, Self::ResultStorage), RuntimeError>
where
Parameters: WitLoad,
Parameters::Layout: Layout<Flat = Self::FlatHostParameters>,
Instance: InstanceWithMemory,
<Instance::Runtime as Runtime>::Memory: RuntimeMemory<Instance>,
{
let (parameters_layout, result_storage_layout) = guest_parameters.split();
let parameters_location = GuestPointer::lift_from(parameters_layout, memory)?;
let parameters = Parameters::load(memory, parameters_location)?;
let result_storage = Self::ResultStorage::lift_from(result_storage_layout, memory)?;
Ok((parameters, result_storage))
}
}