linera_witty/runtime/
traits.rs

1// Copyright (c) Zefchain Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4//! Abstractions over different Wasm runtime implementations.
5
6use std::ops::{Deref, DerefMut};
7
8use frunk::HList;
9
10use super::{memory::Memory, RuntimeError};
11use crate::memory_layout::FlatLayout;
12
13/// A Wasm runtime.
14///
15/// Shared types between different guest instances that use the same runtime.
16pub trait Runtime: Sized {
17    /// A handle to something exported from a guest Wasm module.
18    type Export;
19
20    /// A handle to the guest Wasm module's memory.
21    type Memory;
22}
23
24/// An active guest Wasm module.
25pub trait Instance: Sized {
26    /// The runtime this instance is running in.
27    type Runtime: Runtime;
28
29    /// Custom user data stored in the instance.
30    type UserData;
31
32    /// A reference to the custom user data stored in the instance.
33    type UserDataReference<'a>: Deref<Target = Self::UserData>
34    where
35        Self::UserData: 'a,
36        Self: 'a;
37
38    /// A mutable reference to the custom user data stored in the instance.
39    type UserDataMutReference<'a>: DerefMut<Target = Self::UserData>
40    where
41        Self::UserData: 'a,
42        Self: 'a;
43
44    /// Loads an export from the guest module.
45    fn load_export(&mut self, name: &str) -> Option<<Self::Runtime as Runtime>::Export>;
46
47    /// Returns a reference to the custom user data stored in this instance.
48    fn user_data(&self) -> Self::UserDataReference<'_>;
49
50    /// Returns a mutable reference to the custom user data stored in this instance.
51    fn user_data_mut(&mut self) -> Self::UserDataMutReference<'_>;
52}
53
54/// How a runtime supports a function signature.
55pub trait InstanceWithFunction<Parameters, Results>: Instance
56where
57    Parameters: FlatLayout,
58    Results: FlatLayout,
59{
60    /// The runtime-specific type to represent the function.
61    type Function;
62
63    /// Converts an export into a function, if it is one.
64    fn function_from_export(
65        &mut self,
66        export: <Self::Runtime as Runtime>::Export,
67    ) -> Result<Option<Self::Function>, RuntimeError>;
68
69    /// Calls the `function` from this instance using the specified `parameters`.
70    fn call(
71        &mut self,
72        function: &Self::Function,
73        parameters: Parameters,
74    ) -> Result<Results, RuntimeError>;
75
76    /// Loads a function from the guest Wasm instance.
77    fn load_function(&mut self, name: &str) -> Result<Self::Function, RuntimeError> {
78        let export = self
79            .load_export(name)
80            .ok_or_else(|| RuntimeError::FunctionNotFound(name.to_string()))?;
81
82        self.function_from_export(export)?
83            .ok_or_else(|| RuntimeError::NotAFunction(name.to_string()))
84    }
85}
86
87/// Trait alias for a Wasm module instance with the WIT Canonical ABI `cabi_realloc` function.
88pub trait CabiReallocAlias: InstanceWithFunction<HList![i32, i32, i32, i32], HList![i32]> {}
89
90impl<AnyInstance> CabiReallocAlias for AnyInstance where
91    AnyInstance: InstanceWithFunction<HList![i32, i32, i32, i32], HList![i32]>
92{
93}
94
95/// Trait alias for a Wasm module instance with the WIT Canonical ABI `cabi_free` function.
96pub trait CabiFreeAlias: InstanceWithFunction<HList![i32], HList![]> {}
97
98impl<AnyInstance> CabiFreeAlias for AnyInstance where
99    AnyInstance: InstanceWithFunction<HList![i32], HList![]>
100{
101}
102
103/// Trait alias for a Wasm module instance with the WIT Canonical ABI functions.
104pub trait InstanceWithMemory: CabiReallocAlias + CabiFreeAlias {
105    /// Converts an `export` into the runtime's specific memory type.
106    fn memory_from_export(
107        &self,
108        export: <Self::Runtime as Runtime>::Export,
109    ) -> Result<Option<<Self::Runtime as Runtime>::Memory>, RuntimeError>;
110
111    /// Returns the memory export from the current Wasm module instance.
112    fn memory(&mut self) -> Result<Memory<'_, Self>, RuntimeError> {
113        let export = self
114            .load_export("memory")
115            .ok_or(RuntimeError::MissingMemory)?;
116
117        let memory = self
118            .memory_from_export(export)?
119            .ok_or(RuntimeError::NotMemory)?;
120
121        Ok(Memory::new(self, memory))
122    }
123}