1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
// Copyright (c) Zefchain Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

//! Representation of Wasmer function parameter types.

use frunk::{hlist, hlist_pat, HList};
use wasmer::FromToNativeWasmType;

use crate::{memory_layout::FlatLayout, primitive_types::FlatType};

/// Conversions between flat layouts and Wasmer parameter types.
pub trait WasmerParameters: FlatLayout {
    /// The type Wasmer uses to represent the parameters in a function imported from a guest.
    type ImportParameters;

    /// The type Wasmer uses to represent the parameters in a function exported from a host.
    type ExportParameters;

    /// Converts from this flat layout into Wasmer's representation for functions imported from a
    /// guest.
    fn into_wasmer(self) -> Self::ImportParameters;

    /// Converts from Wasmer's representation for functions exported from the host into this flat
    /// layout.
    fn from_wasmer(parameters: Self::ExportParameters) -> Self;
}

impl WasmerParameters for HList![] {
    type ImportParameters = ();
    type ExportParameters = ();

    fn into_wasmer(self) -> Self::ImportParameters {}

    fn from_wasmer((): Self::ExportParameters) -> Self {
        hlist![]
    }
}

impl<Parameter> WasmerParameters for HList![Parameter]
where
    Parameter: FlatType + FromToNativeWasmType,
{
    type ImportParameters = Parameter;
    type ExportParameters = (Parameter,);

    fn into_wasmer(self) -> Self::ImportParameters {
        let hlist_pat![parameter] = self;

        parameter
    }

    fn from_wasmer((parameter,): Self::ExportParameters) -> Self {
        hlist![parameter]
    }
}

/// Helper macro to implement [`WasmerParameters`] for flat layouts up to the maximum limit.
///
/// The maximum number of parameters is defined by the [canonical
/// ABI](https://github.com/WebAssembly/component-model/blob/main/design/mvp/CanonicalABI.md#flattening)
/// as the `MAX_FLAT_PARAMS` constant. There is no equivalent constant defined in Witty. Instead,
/// any attempt to use more than the limit should lead to a compiler error. Therefore, this macro
/// only implements the trait up to the limit. The same is done in other parts of the code, like
/// for example in
/// [`FlatHostParameters`][`crate::imported_function_interface::FlatHostParameters`].
macro_rules! parameters {
    ($( $names:ident : $types:ident ),*) => {
        impl<$( $types ),*> WasmerParameters for HList![$( $types ),*]
        where
            $( $types: FlatType + FromToNativeWasmType, )*
        {
            type ImportParameters = ($( $types, )*);
            type ExportParameters = ($( $types, )*);

            #[allow(clippy::unused_unit)]
            fn into_wasmer(self) -> Self::ImportParameters {
                let hlist_pat![$( $names ),*] = self;

                ($( $names, )*)
            }

            fn from_wasmer(($( $names, )*): Self::ExportParameters) -> Self {
                hlist![$( $names ),*]
            }
        }
    };
}

repeat_macro!(parameters =>
    a: A,
    b: B |
    c: C,
    d: D,
    e: E,
    f: F,
    g: G,
    h: H,
    i: I,
    j: J,
    k: K,
    l: L,
    m: M,
    n: N,
    o: O,
    p: P,
    q: Q
);