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 Wasmtime function parameter types.

use frunk::{hlist, hlist_pat, HList};
use wasmtime::{WasmParams, WasmTy};

use crate::{primitive_types::FlatType, Layout};

/// Conversions between flat layouts and Wasmtime parameter types.
pub trait WasmtimeParameters {
    /// The type Wasmtime uses to represent the parameters.
    type Parameters: WasmParams;

    /// Converts from this flat layout into Wasmtime's representation.
    fn into_wasmtime(self) -> Self::Parameters;

    /// Converts from Wasmtime's representation into a flat layout.
    fn from_wasmtime(parameters: Self::Parameters) -> Self;
}

/// Helper macro to implement [`WasmtimeParameters`] 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 ),*> WasmtimeParameters for HList![$( $types ),*]
        where
            $( $types: FlatType + WasmTy, )*
        {
            type Parameters = ($( $types, )*);

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

                ($( $names, )*)
            }

            fn from_wasmtime(($( $names, )*): Self::Parameters) -> 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
);

impl<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, Rest> WasmtimeParameters for HList![A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, ...Rest]
where
    A: FlatType,
    B: FlatType,
    C: FlatType,
    D: FlatType,
    E: FlatType,
    F: FlatType,
    G: FlatType,
    H: FlatType,
    I: FlatType,
    J: FlatType,
    K: FlatType,
    L: FlatType,
    M: FlatType,
    N: FlatType,
    O: FlatType,
    P: FlatType,
    Q: FlatType,
    R: FlatType,
    Rest: Layout,
{
    type Parameters = (i32,);

    fn into_wasmtime(self) -> Self::Parameters {
        unreachable!("Attempt to convert a list of flat parameters larger than the maximum limit");
    }

    fn from_wasmtime(_: Self::Parameters) -> Self {
        unreachable!(
            "Attempt to convert into a list of flat parameters larger than the maximum limit"
        );
    }
}