linera_wit_bindgen_host_wasmer_rust/
lib.rs1pub use wit_bindgen_host_wasmer_rust_macro::{export, import};
2
3#[cfg(feature = "tracing-lib")]
4pub use tracing_lib as tracing;
5#[doc(hidden)]
6pub use {anyhow, bitflags, once_cell, wasmer};
7
8mod error;
9mod le;
10mod region;
11mod slab;
12mod table;
13
14pub use error::GuestError;
15pub use le::{Endian, Le};
16pub use region::{AllBytesValid, BorrowChecker, Region};
17pub use table::*;
18
19pub struct RawMemory {
20 pub slice: *mut [u8],
21}
22
23unsafe impl Send for RawMemory {}
27unsafe impl Sync for RawMemory {}
28
29#[doc(hidden)]
30pub mod rt {
31 use crate::slab::Slab;
32 use crate::{Endian, Le};
33 use std::mem;
34 use wasmer::*;
35
36 pub trait RawMem {
37 fn store<T: Endian>(&mut self, offset: i32, val: T) -> Result<(), RuntimeError>;
38 fn store_many<T: Endian>(&mut self, offset: i32, vals: &[T]) -> Result<(), RuntimeError>;
39 fn load<T: Endian>(&self, offset: i32) -> Result<T, RuntimeError>;
40 }
41
42 impl RawMem for [u8] {
43 fn store<T: Endian>(&mut self, offset: i32, val: T) -> Result<(), RuntimeError> {
44 let mem = self
45 .get_mut(offset as usize..)
46 .and_then(|m| m.get_mut(..mem::size_of::<T>()))
47 .ok_or_else(|| RuntimeError::new("out of bounds write"))?;
48 Le::from_slice_mut(mem)[0].set(val);
49 Ok(())
50 }
51
52 fn store_many<T: Endian>(&mut self, offset: i32, val: &[T]) -> Result<(), RuntimeError> {
53 let mem = self
54 .get_mut(offset as usize..)
55 .and_then(|m| {
56 let len = mem::size_of::<T>().checked_mul(val.len())?;
57 m.get_mut(..len)
58 })
59 .ok_or_else(|| RuntimeError::new("out of bounds write"))?;
60 for (slot, val) in Le::from_slice_mut(mem).iter_mut().zip(val) {
61 slot.set(*val);
62 }
63 Ok(())
64 }
65
66 fn load<T: Endian>(&self, offset: i32) -> Result<T, RuntimeError> {
67 let mem = self
68 .get(offset as usize..)
69 .and_then(|m| m.get(..mem::size_of::<Le<T>>()))
70 .ok_or_else(|| RuntimeError::new("out of bounds read"))?;
71 Ok(Le::from_slice(mem)[0].get())
72 }
73 }
74
75 pub fn char_from_i32(val: i32) -> Result<char, RuntimeError> {
76 core::char::from_u32(val as u32)
77 .ok_or_else(|| RuntimeError::new("char value out of valid range"))
78 }
79
80 pub fn invalid_variant(name: &str) -> RuntimeError {
81 let msg = format!("invalid discriminant for `{}`", name);
82 RuntimeError::new(msg)
83 }
84
85 pub fn validate_flags<T, U>(
86 bits: T,
87 all: T,
88 name: &str,
89 mk: impl FnOnce(T) -> U,
90 ) -> Result<U, RuntimeError>
91 where
92 T: std::ops::Not<Output = T> + std::ops::BitAnd<Output = T> + From<u8> + PartialEq + Copy,
93 {
94 if bits & !all != 0u8.into() {
95 let msg = format!("invalid flags specified for `{}`", name);
96 Err(RuntimeError::new(msg))
97 } else {
98 Ok(mk(bits))
99 }
100 }
101
102 pub fn bad_int(_: std::num::TryFromIntError) -> RuntimeError {
103 let msg = "out-of-bounds integer conversion";
104 RuntimeError::new(msg)
105 }
106
107 pub fn copy_slice<T: Endian>(
108 store: &mut wasmer::Store,
109 memory: &Memory,
110 free: &TypedFunction<(i32, i32, i32), ()>,
111 base: i32,
112 len: i32,
113 align: i32,
114 ) -> Result<Vec<T>, RuntimeError> {
115 let size = (len as u32)
116 .checked_mul(mem::size_of::<T>() as u32)
117 .ok_or_else(|| RuntimeError::new("array too large to fit in wasm memory"))?;
118 let memory_view = memory.view(store);
119 let slice = unsafe {
120 memory_view
121 .data_unchecked()
122 .get(base as usize..)
123 .and_then(|s| s.get(..size as usize))
124 .ok_or_else(|| RuntimeError::new("out of bounds read"))?
125 };
126 let result = Le::from_slice(slice).iter().map(|s| s.get()).collect();
127 free.call(store, base, size as i32, align)?;
128 Ok(result)
129 }
130
131 macro_rules! as_traits {
132 ($(($name:ident $tr:ident $ty:ident ($($tys:ident)*)))*) => ($(
133 pub fn $name<T: $tr>(t: T) -> $ty {
134 t.$name()
135 }
136
137 pub trait $tr {
138 fn $name(self) -> $ty;
139 }
140
141 impl<'a, T: Copy + $tr> $tr for &'a T {
142 fn $name(self) -> $ty {
143 (*self).$name()
144 }
145 }
146
147 $(
148 impl $tr for $tys {
149 #[inline]
150 fn $name(self) -> $ty {
151 self as $ty
152 }
153 }
154 )*
155 )*)
156 }
157
158 as_traits! {
159 (as_i32 AsI32 i32 (char i8 u8 i16 u16 i32 u32))
160 (as_i64 AsI64 i64 (i64 u64))
161 (as_f32 AsF32 f32 (f32))
162 (as_f64 AsF64 f64 (f64))
163 }
164
165 #[derive(Default, Debug)]
166 pub struct IndexSlab {
167 slab: Slab<ResourceIndex>,
168 }
169
170 impl IndexSlab {
171 pub fn insert(&mut self, resource: ResourceIndex) -> u32 {
172 self.slab.insert(resource)
173 }
174
175 pub fn get(&self, slab_idx: u32) -> Result<ResourceIndex, RuntimeError> {
176 match self.slab.get(slab_idx) {
177 Some(idx) => Ok(*idx),
178 None => Err(RuntimeError::new("invalid index specified for handle")),
179 }
180 }
181
182 pub fn remove(&mut self, slab_idx: u32) -> Result<ResourceIndex, RuntimeError> {
183 match self.slab.remove(slab_idx) {
184 Some(idx) => Ok(idx),
185 None => Err(RuntimeError::new("invalid index specified for handle")),
186 }
187 }
188 }
189
190 #[derive(Default, Debug)]
191 pub struct ResourceSlab {
192 slab: Slab<Resource>,
193 }
194
195 #[derive(Debug)]
196 struct Resource {
197 wasm: i32,
198 refcnt: u32,
199 }
200
201 #[derive(Debug, Copy, Clone)]
202 pub struct ResourceIndex(u32);
203
204 impl ResourceSlab {
205 pub fn insert(&mut self, wasm: i32) -> ResourceIndex {
206 ResourceIndex(self.slab.insert(Resource { wasm, refcnt: 1 }))
207 }
208
209 pub fn get(&self, idx: ResourceIndex) -> i32 {
210 self.slab.get(idx.0).unwrap().wasm
211 }
212
213 pub fn clone(&mut self, idx: ResourceIndex) -> Result<(), RuntimeError> {
214 let resource = self.slab.get_mut(idx.0).unwrap();
215 resource.refcnt = match resource.refcnt.checked_add(1) {
216 Some(cnt) => cnt,
217 None => return Err(RuntimeError::new("resource index count overflow")),
218 };
219 Ok(())
220 }
221
222 pub fn drop(&mut self, idx: ResourceIndex) -> Option<i32> {
223 let resource = self.slab.get_mut(idx.0).unwrap();
224 assert!(resource.refcnt > 0);
225 resource.refcnt -= 1;
226 if resource.refcnt != 0 {
227 return None;
228 }
229 let resource = self.slab.remove(idx.0).unwrap();
230 Some(resource.wasm)
231 }
232 }
233}