extism_pdk/
memory.rs

1use crate::*;
2
3pub struct Memory(pub MemoryHandle);
4
5pub struct ManagedMemory(pub Memory);
6
7pub mod internal {
8    use super::*;
9
10    pub fn memory_alloc(n: u64) -> MemoryHandle {
11        let length = n;
12        let offset = unsafe { extism::alloc(length) };
13        MemoryHandle { offset, length }
14    }
15
16    pub fn memory_free(handle: MemoryHandle) {
17        unsafe { extism::free(handle.offset) }
18    }
19
20    pub fn memory_bytes(handle: MemoryHandle) -> Vec<u8> {
21        let mut data = vec![0; handle.length as usize];
22        unsafe { extism::load(handle.offset, &mut data) };
23        data
24    }
25
26    /// Get the length of the memory handle stored at the given offset, this will return 0 if called on a non-handle pointer
27    pub fn memory_length(offs: u64) -> u64 {
28        unsafe { extism::length(offs) }
29    }
30
31    /// Get the length of the memory handle stored at the given offset, this may return garbage if called on a non-handle pointer
32    pub fn memory_length_unsafe(offs: u64) -> u64 {
33        unsafe { extism::length_unsafe(offs) }
34    }
35
36    /// Load data from memory into a `u8` slice
37    pub fn load(handle: MemoryHandle, mut buf: impl AsMut<[u8]>) {
38        let buf = buf.as_mut();
39        unsafe {
40            extism::load(handle.offset, &mut buf[0..handle.length as usize]);
41        }
42    }
43
44    /// Load data from `u8` slice into memory
45    pub fn store(handle: MemoryHandle, buf: impl AsRef<[u8]>) {
46        let buf = buf.as_ref();
47        unsafe { extism::store(handle.offset, &buf[0..handle.length as usize]) }
48    }
49
50    /// Find `Memory` by offset
51    pub fn find(offset: u64) -> Option<MemoryHandle> {
52        let length = unsafe { extism::length(offset) };
53
54        if length == 0 {
55            return None;
56        }
57
58        Some(MemoryHandle { offset, length })
59    }
60}
61
62impl Memory {
63    pub fn offset(&self) -> u64 {
64        self.0.offset
65    }
66
67    pub fn len(&self) -> usize {
68        self.0.length as usize
69    }
70
71    pub fn is_empty(&self) -> bool {
72        self.0.length == 0
73    }
74
75    pub fn null() -> Self {
76        Memory(MemoryHandle {
77            offset: 0,
78            length: 0,
79        })
80    }
81
82    /// Allocate a new block with an encoded value
83    pub fn new<'a, T: ToBytes<'a>>(x: &T) -> Result<Self, Error> {
84        let data = x.to_bytes()?;
85        let data = data.as_ref();
86        let length = data.len() as u64;
87        let offset = unsafe { extism::alloc(length) };
88        unsafe { extism::store(offset, data) };
89        Ok(Self(MemoryHandle { offset, length }))
90    }
91
92    /// Create a memory block and copy bytes from `u8` slice
93    pub fn from_bytes(data: impl AsRef<[u8]>) -> Result<Self, Error> {
94        let memory = Memory::new(&data.as_ref())?;
95        Ok(memory)
96    }
97
98    /// Copy data out of memory and into a vec
99    pub fn to_vec(&self) -> Vec<u8> {
100        let mut dest = vec![0u8; self.0.length as usize];
101        internal::load(self.0, &mut dest);
102        dest
103    }
104
105    /// Copy data out of memory and convert to string
106    pub fn to_string(&self) -> Result<String, Error> {
107        let x = String::from_utf8(self.to_vec())?;
108        Ok(x)
109    }
110
111    /// Store memory as function output
112    pub fn set_output(self) {
113        unsafe {
114            extism::output_set(self.0.offset, self.0.length);
115        }
116    }
117
118    /// Log memory
119    pub fn log(&self, level: LogLevel) {
120        unsafe {
121            match level {
122                LogLevel::Info => extism::log_info(self.0.offset),
123                LogLevel::Debug => extism::log_debug(self.0.offset),
124                LogLevel::Warn => extism::log_warn(self.0.offset),
125                LogLevel::Error => extism::log_error(self.0.offset),
126                LogLevel::Trace => extism::log_trace(self.0.offset),
127            }
128        }
129    }
130
131    /// Convert to a Rust value
132    pub fn to<T: FromBytesOwned>(&self) -> Result<T, Error> {
133        T::from_bytes_owned(&self.to_vec())
134    }
135
136    /// Locate a memory block by offset
137    pub fn find(offs: u64) -> Option<Memory> {
138        internal::find(offs).map(Memory)
139    }
140
141    /// Free a memory block, allowing for it to be re-used
142    pub fn free(self) {
143        internal::memory_free(self.0)
144    }
145}
146
147impl From<Memory> for () {
148    fn from(_: Memory) {}
149}
150
151impl From<()> for Memory {
152    fn from(_: ()) -> Memory {
153        Memory(MemoryHandle::null())
154    }
155}
156
157impl From<Memory> for i64 {
158    fn from(m: Memory) -> Self {
159        m.0.offset as i64
160    }
161}
162
163impl From<Memory> for u64 {
164    fn from(m: Memory) -> Self {
165        m.0.offset
166    }
167}
168
169impl From<u64> for Memory {
170    fn from(offset: u64) -> Memory {
171        Memory::find(offset).unwrap_or_else(Memory::null)
172    }
173}
174
175impl From<i64> for Memory {
176    fn from(offset: i64) -> Memory {
177        Memory::find(offset as u64).unwrap_or_else(Memory::null)
178    }
179}
180
181#[repr(transparent)]
182#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
183pub struct MemoryPointer<T>(u64, std::marker::PhantomData<T>);
184
185impl<T> MemoryPointer<T> {
186    pub unsafe fn new(x: u64) -> Self {
187        MemoryPointer(x, Default::default())
188    }
189}
190
191impl<T: FromBytesOwned> MemoryPointer<T> {
192    pub fn get(&self) -> Result<T, Error> {
193        let mem = Memory::find(self.0);
194        match mem {
195            Some(mem) => T::from_bytes_owned(&mem.to_vec()),
196            None => anyhow::bail!("Invalid pointer offset {}", self.0),
197        }
198    }
199}
200
201impl Drop for ManagedMemory {
202    fn drop(&mut self) {
203        internal::memory_free((self.0).0)
204    }
205}
206
207impl ManagedMemory {
208    pub fn new(mem: Memory) -> Self {
209        ManagedMemory(mem)
210    }
211
212    pub fn offset(&self) -> u64 {
213        self.0.offset()
214    }
215
216    pub fn len(&self) -> usize {
217        self.0.len()
218    }
219}
220
221impl From<Memory> for ManagedMemory {
222    fn from(value: Memory) -> Self {
223        ManagedMemory(value)
224    }
225}
226
227impl AsRef<Memory> for ManagedMemory {
228    fn as_ref(&self) -> &Memory {
229        &self.0
230    }
231}
232
233impl AsMut<Memory> for ManagedMemory {
234    fn as_mut(&mut self) -> &mut Memory {
235        &mut self.0
236    }
237}