1#![cfg_attr(not(feature = "std"), no_std)]
21
22use tetcore_std::{
23 vec,
24 borrow::Cow, marker::PhantomData, mem, iter::Iterator, result, vec::Vec,
25};
26
27#[cfg(feature = "std")]
28mod twasmi_impl;
29
30#[cfg(feature = "std")]
32pub type Result<T> = result::Result<T, String>;
33#[cfg(not(feature = "std"))]
34pub type Result<T> = result::Result<T, &'static str>;
35
36#[derive(Copy, Clone, PartialEq, Debug, Eq)]
38pub enum ValueType {
39 I32,
41 I64,
43 F32,
45 F64,
47}
48
49impl From<ValueType> for u8 {
50 fn from(val: ValueType) -> u8 {
51 match val {
52 ValueType::I32 => 0,
53 ValueType::I64 => 1,
54 ValueType::F32 => 2,
55 ValueType::F64 => 3,
56 }
57 }
58}
59
60impl tetcore_std::convert::TryFrom<u8> for ValueType {
61 type Error = ();
62
63 fn try_from(val: u8) -> tetcore_std::result::Result<ValueType, ()> {
64 match val {
65 0 => Ok(Self::I32),
66 1 => Ok(Self::I64),
67 2 => Ok(Self::F32),
68 3 => Ok(Self::F64),
69 _ => Err(()),
70 }
71 }
72}
73
74#[derive(PartialEq, Debug, Clone, Copy, codec::Encode, codec::Decode)]
76pub enum Value {
77 I32(i32),
79 I64(i64),
81 F32(u32),
85 F64(u64),
89}
90
91impl Value {
92 pub fn value_type(&self) -> ValueType {
94 match self {
95 Value::I32(_) => ValueType::I32,
96 Value::I64(_) => ValueType::I64,
97 Value::F32(_) => ValueType::F32,
98 Value::F64(_) => ValueType::F64,
99 }
100 }
101
102 pub fn as_i32(&self) -> Option<i32> {
104 match self {
105 Self::I32(val) => Some(*val),
106 _ => None,
107 }
108 }
109}
110
111mod private {
113 pub trait Sealed {}
114
115 impl Sealed for u8 {}
116 impl Sealed for u16 {}
117 impl Sealed for u32 {}
118 impl Sealed for u64 {}
119}
120
121pub trait PointerType: Sized + private::Sealed {
125 const SIZE: u32 = mem::size_of::<Self>() as u32;
127}
128
129impl PointerType for u8 {}
130impl PointerType for u16 {}
131impl PointerType for u32 {}
132impl PointerType for u64 {}
133
134#[derive(Debug, PartialEq, Eq, Clone, Copy)]
136pub struct Pointer<T: PointerType> {
137 ptr: u32,
138 _marker: PhantomData<T>,
139}
140
141impl<T: PointerType> Pointer<T> {
142 pub fn new(ptr: u32) -> Self {
144 Self {
145 ptr,
146 _marker: Default::default(),
147 }
148 }
149
150 pub fn offset(self, offset: u32) -> Option<Self> {
156 offset.checked_mul(T::SIZE).and_then(|o| self.ptr.checked_add(o)).map(|ptr| {
157 Self {
158 ptr,
159 _marker: Default::default(),
160 }
161 })
162 }
163
164 pub fn null() -> Self {
166 Self::new(0)
167 }
168
169 pub fn cast<R: PointerType>(self) -> Pointer<R> {
171 Pointer::new(self.ptr)
172 }
173}
174
175impl<T: PointerType> From<u32> for Pointer<T> {
176 fn from(ptr: u32) -> Self {
177 Pointer::new(ptr)
178 }
179}
180
181impl<T: PointerType> From<Pointer<T>> for u32 {
182 fn from(ptr: Pointer<T>) -> Self {
183 ptr.ptr
184 }
185}
186
187impl<T: PointerType> From<Pointer<T>> for u64 {
188 fn from(ptr: Pointer<T>) -> Self {
189 u64::from(ptr.ptr)
190 }
191}
192
193impl<T: PointerType> From<Pointer<T>> for usize {
194 fn from(ptr: Pointer<T>) -> Self {
195 ptr.ptr as _
196 }
197}
198
199impl<T: PointerType> IntoValue for Pointer<T> {
200 const VALUE_TYPE: ValueType = ValueType::I32;
201 fn into_value(self) -> Value { Value::I32(self.ptr as _) }
202}
203
204impl<T: PointerType> TryFromValue for Pointer<T> {
205 fn try_from_value(val: Value) -> Option<Self> {
206 match val {
207 Value::I32(val) => Some(Self::new(val as _)),
208 _ => None,
209 }
210 }
211}
212
213pub type WordSize = u32;
215
216#[derive(Eq, PartialEq, Debug, Clone)]
218pub struct Signature {
219 pub args: Cow<'static, [ValueType]>,
221 pub return_value: Option<ValueType>,
223}
224
225impl Signature {
226 pub fn new<T: Into<Cow<'static, [ValueType]>>>(args: T, return_value: Option<ValueType>) -> Self {
228 Self {
229 args: args.into(),
230 return_value,
231 }
232 }
233
234 pub fn new_with_args<T: Into<Cow<'static, [ValueType]>>>(args: T) -> Self {
236 Self {
237 args: args.into(),
238 return_value: None,
239 }
240 }
241}
242
243#[cfg(feature = "std")]
245pub trait MaybeRefUnwindSafe: std::panic::RefUnwindSafe {}
246#[cfg(feature = "std")]
247impl<T: std::panic::RefUnwindSafe> MaybeRefUnwindSafe for T {}
248
249#[cfg(not(feature = "std"))]
251pub trait MaybeRefUnwindSafe {}
252#[cfg(not(feature = "std"))]
253impl<T> MaybeRefUnwindSafe for T {}
254
255pub trait Function: MaybeRefUnwindSafe + Send + Sync {
257 fn name(&self) -> &str;
259 fn signature(&self) -> Signature;
261 fn execute(
263 &self,
264 context: &mut dyn FunctionContext,
265 args: &mut dyn Iterator<Item = Value>,
266 ) -> Result<Option<Value>>;
267}
268
269impl PartialEq for dyn Function {
270 fn eq(&self, other: &Self) -> bool {
271 other.name() == self.name() && other.signature() == self.signature()
272 }
273}
274
275pub trait FunctionContext {
277 fn read_memory(&self, address: Pointer<u8>, size: WordSize) -> Result<Vec<u8>> {
279 let mut vec = vec![0; size as usize];
280 self.read_memory_into(address, &mut vec)?;
281 Ok(vec)
282 }
283 fn read_memory_into(&self, address: Pointer<u8>, dest: &mut [u8]) -> Result<()>;
285 fn write_memory(&mut self, address: Pointer<u8>, data: &[u8]) -> Result<()>;
287 fn allocate_memory(&mut self, size: WordSize) -> Result<Pointer<u8>>;
289 fn deallocate_memory(&mut self, ptr: Pointer<u8>) -> Result<()>;
291 fn sandbox(&mut self) -> &mut dyn Sandbox;
293}
294
295pub type MemoryId = u32;
297
298pub trait Sandbox {
300 fn memory_get(
302 &mut self,
303 memory_id: MemoryId,
304 offset: WordSize,
305 buf_ptr: Pointer<u8>,
306 buf_len: WordSize,
307 ) -> Result<u32>;
308 fn memory_set(
310 &mut self,
311 memory_id: MemoryId,
312 offset: WordSize,
313 val_ptr: Pointer<u8>,
314 val_len: WordSize,
315 ) -> Result<u32>;
316 fn memory_teardown(&mut self, memory_id: MemoryId) -> Result<()>;
318 fn memory_new(&mut self, initial: u32, maximum: u32) -> Result<MemoryId>;
321 fn invoke(
323 &mut self,
324 instance_id: u32,
325 export_name: &str,
326 args: &[u8],
327 return_val: Pointer<u8>,
328 return_val_len: WordSize,
329 state: u32,
330 ) -> Result<u32>;
331 fn instance_teardown(&mut self, instance_id: u32) -> Result<()>;
333 fn instance_new(
335 &mut self,
336 dispatch_thunk_id: u32,
337 wasm: &[u8],
338 raw_env_def: &[u8],
339 state: u32,
340 ) -> Result<u32>;
341
342 fn get_global_val(&self, instance_idx: u32, name: &str) -> Result<Option<Value>>;
347}
348
349pub trait HostFunctions: 'static {
351 fn host_functions() -> Vec<&'static dyn Function>;
353}
354
355#[impl_trait_for_tuples::impl_for_tuples(30)]
356impl HostFunctions for Tuple {
357 fn host_functions() -> Vec<&'static dyn Function> {
358 let mut host_functions = Vec::new();
359
360 for_tuples!( #( host_functions.extend(Tuple::host_functions()); )* );
361
362 host_functions
363 }
364}
365
366pub trait IntoValue {
368 const VALUE_TYPE: ValueType;
370
371 fn into_value(self) -> Value;
373}
374
375pub trait TryFromValue: Sized {
377 fn try_from_value(val: Value) -> Option<Self>;
379}
380
381macro_rules! impl_into_and_from_value {
382 (
383 $(
384 $type:ty, $( < $gen:ident >, )? $value_variant:ident,
385 )*
386 ) => {
387 $(
388 impl $( <$gen> )? IntoValue for $type {
389 const VALUE_TYPE: ValueType = ValueType::$value_variant;
390 fn into_value(self) -> Value { Value::$value_variant(self as _) }
391 }
392
393 impl $( <$gen> )? TryFromValue for $type {
394 fn try_from_value(val: Value) -> Option<Self> {
395 match val {
396 Value::$value_variant(val) => Some(val as _),
397 _ => None,
398 }
399 }
400 }
401 )*
402 }
403}
404
405impl_into_and_from_value! {
406 u8, I32,
407 u16, I32,
408 u32, I32,
409 u64, I64,
410 i8, I32,
411 i16, I32,
412 i32, I32,
413 i64, I64,
414}
415
416pub trait WritePrimitive<T: PointerType> {
418 fn write_primitive(&mut self, ptr: Pointer<T>, t: T) -> Result<()>;
420}
421
422impl WritePrimitive<u32> for &mut dyn FunctionContext {
423 fn write_primitive(&mut self, ptr: Pointer<u32>, t: u32) -> Result<()> {
424 let r = t.to_le_bytes();
425 self.write_memory(ptr.cast(), &r)
426 }
427}
428
429impl WritePrimitive<u64> for &mut dyn FunctionContext {
430 fn write_primitive(&mut self, ptr: Pointer<u64>, t: u64) -> Result<()> {
431 let r = t.to_le_bytes();
432 self.write_memory(ptr.cast(), &r)
433 }
434}
435
436pub trait ReadPrimitive<T: PointerType> {
438 fn read_primitive(&self, ptr: Pointer<T>) -> Result<T>;
440}
441
442impl ReadPrimitive<u32> for &mut dyn FunctionContext {
443 fn read_primitive(&self, ptr: Pointer<u32>) -> Result<u32> {
444 let mut r = [0u8; 4];
445 self.read_memory_into(ptr.cast(), &mut r)?;
446 Ok(u32::from_le_bytes(r))
447 }
448}
449
450impl ReadPrimitive<u64> for &mut dyn FunctionContext {
451 fn read_primitive(&self, ptr: Pointer<u64>) -> Result<u64> {
452 let mut r = [0u8; 8];
453 self.read_memory_into(ptr.cast(), &mut r)?;
454 Ok(u64::from_le_bytes(r))
455 }
456}
457
458#[derive(Clone, Copy, PartialEq, codec::Encode, codec::Decode, Debug)]
462pub enum ReturnValue {
463 Unit,
465 Value(Value),
467}
468
469impl From<Value> for ReturnValue {
470 fn from(v: Value) -> ReturnValue {
471 ReturnValue::Value(v)
472 }
473}
474
475impl ReturnValue {
476 pub const ENCODED_MAX_SIZE: usize = 10;
483}
484
485#[cfg(test)]
486mod tests {
487 use super::*;
488 use codec::Encode;
489
490 #[test]
491 fn pointer_offset_works() {
492 let ptr = Pointer::<u32>::null();
493
494 assert_eq!(ptr.offset(10).unwrap(), Pointer::new(40));
495 assert_eq!(ptr.offset(32).unwrap(), Pointer::new(128));
496
497 let ptr = Pointer::<u64>::null();
498
499 assert_eq!(ptr.offset(10).unwrap(), Pointer::new(80));
500 assert_eq!(ptr.offset(32).unwrap(), Pointer::new(256));
501 }
502
503
504 #[test]
505 fn return_value_encoded_max_size() {
506 let encoded = ReturnValue::Value(Value::I64(-1)).encode();
507 assert_eq!(encoded.len(), ReturnValue::ENCODED_MAX_SIZE);
508 }
509}