surrealism_types/controller.rs
1//! Memory management abstractions for WASM linear memory.
2//!
3//! This module defines traits for allocating and deallocating memory in WASM linear memory,
4//! as well as accessing that memory. It provides both synchronous (guest-side) and
5//! asynchronous (host-side) interfaces.
6//!
7//! # Memory Model
8//!
9//! WASM uses a linear memory model - a contiguous array of bytes that can grow over time.
10//! The memory controller abstractions allow:
11//!
12//! - **Allocation**: Reserve a region of memory with specific size and alignment
13//! - **Deallocation**: Free a previously allocated region
14//! - **Access**: Read and write to memory regions via byte slices
15//!
16//! # Safety
17//!
18//! While these traits provide safe Rust interfaces, they operate on raw memory pointers.
19//! Implementations must ensure:
20//! - Allocated pointers are valid and within bounds
21//! - Deallocations match previous allocations
22//! - Memory access doesn't exceed allocated regions
23//! - Alignment requirements are respected
24
25use anyhow::Result;
26#[cfg(feature = "host")]
27use async_trait::async_trait;
28
29/// Synchronous memory controller for WASM linear memory (guest side).
30///
31/// This trait provides the interface for managing memory allocations within a WASM module.
32/// It's designed to be used on the guest side where all operations are synchronous.
33///
34/// # Implementation Notes
35///
36/// Implementers typically:
37/// - Use the WASM allocator (`__alloc`, `__free` exports)
38/// - Track allocations for cleanup
39/// - Validate alignment and bounds
40///
41/// # Example
42///
43/// ```rust,ignore
44/// use surrealism_types::MemoryController;
45///
46/// struct MyController {
47/// memory: Vec<u8>,
48/// }
49///
50/// impl MemoryController for MyController {
51/// fn alloc(&mut self, len: u32, align: u32) -> Result<u32> {
52/// // Allocate aligned memory...
53/// Ok(ptr)
54/// }
55///
56/// fn free(&mut self, ptr: u32, len: u32) -> Result<()> {
57/// // Deallocate memory...
58/// Ok(())
59/// }
60///
61/// fn mut_mem(&mut self, ptr: u32, len: u32) -> &mut [u8] {
62/// // Return mutable slice to memory region...
63/// &mut self.memory[ptr as usize..(ptr + len) as usize]
64/// }
65/// }
66/// ```
67pub trait MemoryController {
68 /// Allocate a region of WASM linear memory.
69 ///
70 /// # Parameters
71 ///
72 /// - `len`: Number of bytes to allocate
73 /// - `align`: Alignment requirement in bytes (must be a power of 2)
74 ///
75 /// # Returns
76 ///
77 /// A pointer (`u32`) to the start of the allocated region.
78 ///
79 /// # Errors
80 ///
81 /// Returns an error if:
82 /// - Allocation fails (out of memory)
83 /// - Alignment is invalid (not a power of 2)
84 /// - Memory limit would be exceeded
85 fn alloc(&mut self, len: u32) -> Result<u32>;
86
87 /// Free a previously allocated region of memory.
88 ///
89 /// # Parameters
90 ///
91 /// - `ptr`: Pointer to the start of the region (from a previous `alloc` call)
92 /// - `len`: Size of the region in bytes (must match the original allocation)
93 ///
94 /// # Errors
95 ///
96 /// Returns an error if:
97 /// - The pointer is invalid or wasn't allocated
98 /// - The length doesn't match the original allocation
99 /// - Double-free is detected
100 ///
101 /// # Safety Notes
102 ///
103 /// After calling `free`, the pointer and any references to that memory region
104 /// become invalid and must not be used.
105 fn free(&mut self, ptr: u32, len: u32) -> Result<()>;
106
107 /// Get mutable access to a region of WASM linear memory.
108 ///
109 /// # Parameters
110 ///
111 /// - `ptr`: Pointer to the start of the region
112 /// - `len`: Length of the region in bytes
113 ///
114 /// # Returns
115 ///
116 /// A mutable slice to the memory region.
117 ///
118 /// # Panics
119 ///
120 /// May panic if the pointer or length are out of bounds. Implementations should
121 /// validate bounds before returning the slice.
122 fn mut_mem(&mut self, ptr: u32, len: u32) -> &mut [u8];
123}
124
125/// Asynchronous memory controller for WASM linear memory (host side).
126///
127/// This trait provides an async interface for managing memory allocations when
128/// interacting with a WASM module from the host (runtime). It mirrors [`MemoryController`]
129/// but with async methods to support asynchronous runtimes like Tokio.
130///
131/// # Feature Gate
132///
133/// This trait is only available when the `host` feature is enabled.
134///
135/// # Example
136///
137/// ```rust,ignore
138/// use surrealism_types::AsyncMemoryController;
139/// use async_trait::async_trait;
140///
141/// struct MyAsyncController {
142/// // ... state ...
143/// }
144///
145/// #[async_trait]
146/// impl AsyncMemoryController for MyAsyncController {
147/// async fn alloc(&mut self, len: u32, align: u32) -> Result<u32> {
148/// // Call WASM allocator function asynchronously...
149/// Ok(ptr)
150/// }
151///
152/// async fn free(&mut self, ptr: u32, len: u32) -> Result<()> {
153/// // Call WASM deallocator function asynchronously...
154/// Ok(())
155/// }
156///
157/// fn mut_mem(&mut self, ptr: u32, len: u32) -> &mut [u8] {
158/// // Access WASM memory (synchronous)...
159/// &mut memory[ptr as usize..(ptr + len) as usize]
160/// }
161/// }
162/// ```
163#[cfg(feature = "host")]
164#[async_trait]
165pub trait AsyncMemoryController: Send {
166 /// Allocate a region of WASM linear memory (async).
167 ///
168 /// # Parameters
169 ///
170 /// - `len`: Number of bytes to allocate
171 /// - `align`: Alignment requirement in bytes (must be a power of 2)
172 ///
173 /// # Returns
174 ///
175 /// A pointer (`u32`) to the start of the allocated region.
176 ///
177 /// # Errors
178 ///
179 /// Returns an error if:
180 /// - Allocation fails (out of memory)
181 /// - Alignment is invalid (not a power of 2)
182 /// - WASM function call fails
183 async fn alloc(&mut self, len: u32) -> Result<u32>;
184
185 /// Free a previously allocated region of memory (async).
186 ///
187 /// # Parameters
188 ///
189 /// - `ptr`: Pointer to the start of the region (from a previous `alloc` call)
190 /// - `len`: Size of the region in bytes (must match the original allocation)
191 ///
192 /// # Errors
193 ///
194 /// Returns an error if:
195 /// - The pointer is invalid or wasn't allocated
196 /// - The length doesn't match the original allocation
197 /// - WASM function call fails
198 async fn free(&mut self, ptr: u32, len: u32) -> Result<()>;
199
200 /// Get mutable access to a region of WASM linear memory.
201 ///
202 /// Note: This method is synchronous even in the async trait because memory
203 /// access itself doesn't require async operations - only the allocation/deallocation
204 /// involves calling WASM functions.
205 ///
206 /// # Parameters
207 ///
208 /// - `ptr`: Pointer to the start of the region
209 /// - `len`: Length of the region in bytes
210 ///
211 /// # Returns
212 ///
213 /// A mutable slice to the memory region.
214 ///
215 /// # Panics
216 ///
217 /// May panic if the pointer or length are out of bounds.
218 fn mut_mem(&mut self, ptr: u32, len: u32) -> Result<&mut [u8]>;
219}