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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// Copyright (c) Zefchain Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

//! Helper traits for exporting host functions to guest Wasm instances.
//!
//! These help determining the function signature the guest expects based on the host function
//! signature.

mod guest_interface;
mod result_storage;

use self::{guest_interface::GuestInterface, result_storage::ResultStorage};
use crate::{
    InstanceWithMemory, Layout, Memory, Runtime, RuntimeError, RuntimeMemory, WitLoad, WitStore,
    WitType,
};

/// A type that can register some functions as exports for the target `Instance`.
pub trait ExportTo<Instance> {
    /// Registers some host functions as exports to the provided guest Wasm `instance`.
    fn export_to(instance: &mut Instance) -> Result<(), RuntimeError>;
}

/// A type that accepts registering a host function as an export for a guest Wasm instance.
///
/// The `Handler` represents the closure type required for the host function, and `Parameters` and
/// `Results` are the input and output types of the closure, respectively.
pub trait ExportFunction<Handler, Parameters, Results> {
    /// Registers a host function executed by the `handler` with the provided `module_name` and
    /// `function_name` as an export for a guest Wasm instance.
    fn export(
        &mut self,
        module_name: &str,
        function_name: &str,
        handler: Handler,
    ) -> Result<(), RuntimeError>;
}

/// Representation of an exported host function's interface.
///
/// Implemented for a tuple pair of the host parameters type and the host results type, and allows
/// converting to the signature the guest Wasm instance uses for that host function.
pub trait ExportedFunctionInterface {
    /// The type representing the host-side parameters.
    type HostParameters: WitType;

    /// The type representing the host-side results.
    type HostResults: WitStore;

    /// The representation of the guest-side function interface.
    type GuestInterface: GuestInterface<
        FlatHostParameters = <<Self::HostParameters as WitType>::Layout as Layout>::Flat,
        ResultStorage = Self::ResultStorage,
    >;

    /// The type representing the guest-side parameters.
    type GuestParameters;

    /// The type representing the guest-side results.
    type GuestResults;

    /// How the results from the exported host function should be sent back to the guest.
    type ResultStorage: ResultStorage<OutputFor<Self::HostResults> = Self::GuestResults>;

    /// Converts the guest-side parameters into the host-side parameters.
    fn lift_parameters<Instance>(
        guest_parameters: Self::GuestParameters,
        memory: &Memory<'_, Instance>,
    ) -> Result<(Self::HostParameters, Self::ResultStorage), RuntimeError>
    where
        Instance: InstanceWithMemory,
        <Instance::Runtime as Runtime>::Memory: RuntimeMemory<Instance>;

    /// Converts the host-side results into the guest-side results.
    fn lower_results<Instance>(
        results: Self::HostResults,
        result_storage: Self::ResultStorage,
        memory: &mut Memory<'_, Instance>,
    ) -> Result<Self::GuestResults, RuntimeError>
    where
        Instance: InstanceWithMemory,
        <Instance::Runtime as Runtime>::Memory: RuntimeMemory<Instance>;
}

impl<Parameters, Results> ExportedFunctionInterface for (Parameters, Results)
where
    Parameters: WitLoad,
    Results: WitStore,
    (
        <Parameters::Layout as Layout>::Flat,
        <Results::Layout as Layout>::Flat,
    ): GuestInterface<FlatHostParameters = <Parameters::Layout as Layout>::Flat>,
    <() as WitType>::Layout: Layout<Flat = frunk::HNil>,
{
    type HostParameters = Parameters;
    type HostResults = Results;
    type GuestInterface = (
        <Parameters::Layout as Layout>::Flat,
        <Results::Layout as Layout>::Flat,
    );
    type GuestParameters = <Self::GuestInterface as GuestInterface>::FlatGuestParameters;
    type GuestResults =
        <<Self::GuestInterface as GuestInterface>::ResultStorage as ResultStorage>::OutputFor<
            Self::HostResults,
        >;
    type ResultStorage = <Self::GuestInterface as GuestInterface>::ResultStorage;

    fn lift_parameters<Instance>(
        guest_parameters: Self::GuestParameters,
        memory: &Memory<'_, Instance>,
    ) -> Result<(Self::HostParameters, Self::ResultStorage), RuntimeError>
    where
        Instance: InstanceWithMemory,
        <Instance::Runtime as Runtime>::Memory: RuntimeMemory<Instance>,
    {
        Self::GuestInterface::lift_parameters(guest_parameters, memory)
    }

    fn lower_results<Instance>(
        results: Self::HostResults,
        result_storage: Self::ResultStorage,
        memory: &mut Memory<'_, Instance>,
    ) -> Result<Self::GuestResults, RuntimeError>
    where
        Instance: InstanceWithMemory,
        <Instance::Runtime as Runtime>::Memory: RuntimeMemory<Instance>,
    {
        result_storage.lower_result(results, memory)
    }
}