1use crate::{memory::MemoryType, module::ModuleInfo, structures::TypedIndex, units::Pages};
5use std::{borrow::Cow, convert::TryFrom};
6
7#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash)]
9pub enum Type {
10    I32,
12    I64,
14    F32,
16    F64,
18    V128,
20}
21
22impl std::fmt::Display for Type {
23    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
24        write!(f, "{:?}", self)
25    }
26}
27
28#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
33pub enum Value {
34    I32(i32),
36    I64(i64),
38    F32(f32),
40    F64(f64),
42    V128(u128),
44}
45
46impl Value {
47    pub fn ty(&self) -> Type {
49        match self {
50            Value::I32(_) => Type::I32,
51            Value::I64(_) => Type::I64,
52            Value::F32(_) => Type::F32,
53            Value::F64(_) => Type::F64,
54            Value::V128(_) => Type::V128,
55        }
56    }
57
58    pub fn to_u128(&self) -> u128 {
60        match *self {
61            Value::I32(x) => x as u128,
62            Value::I64(x) => x as u128,
63            Value::F32(x) => f32::to_bits(x) as u128,
64            Value::F64(x) => f64::to_bits(x) as u128,
65            Value::V128(x) => x,
66        }
67    }
68}
69
70macro_rules! value_conversions {
71    ($native_type:ty, $value_variant:ident) => {
72        impl From<$native_type> for Value {
73            fn from(n: $native_type) -> Self {
74                Self::$value_variant(n)
75            }
76        }
77
78        impl TryFrom<&Value> for $native_type {
79            type Error = &'static str;
80
81            fn try_from(value: &Value) -> Result<Self, Self::Error> {
82                match value {
83                    Value::$value_variant(value) => Ok(*value),
84                    _ => Err("Invalid cast."),
85                }
86            }
87        }
88    };
89}
90
91value_conversions!(i32, I32);
92value_conversions!(i64, I64);
93value_conversions!(f32, F32);
94value_conversions!(f64, F64);
95value_conversions!(u128, V128);
96
97pub unsafe trait NativeWasmType: Copy + Into<Value>
99where
100    Self: Sized,
101{
102    const TYPE: Type;
104
105    fn from_binary(bits: u64) -> Self;
107
108    fn to_binary(self) -> u64;
110}
111
112unsafe impl NativeWasmType for i32 {
113    const TYPE: Type = Type::I32;
114
115    fn from_binary(bits: u64) -> Self {
116        bits as _
117    }
118
119    fn to_binary(self) -> u64 {
120        self as _
121    }
122}
123
124unsafe impl NativeWasmType for i64 {
125    const TYPE: Type = Type::I64;
126
127    fn from_binary(bits: u64) -> Self {
128        bits as _
129    }
130
131    fn to_binary(self) -> u64 {
132        self as _
133    }
134}
135
136unsafe impl NativeWasmType for f32 {
137    const TYPE: Type = Type::F32;
138
139    fn from_binary(bits: u64) -> Self {
140        f32::from_bits(bits as u32)
141    }
142
143    fn to_binary(self) -> u64 {
144        self.to_bits() as _
145    }
146}
147
148unsafe impl NativeWasmType for f64 {
149    const TYPE: Type = Type::F64;
150
151    fn from_binary(bits: u64) -> Self {
152        f64::from_bits(bits)
153    }
154
155    fn to_binary(self) -> u64 {
156        self.to_bits()
157    }
158}
159
160pub unsafe trait WasmExternType: Copy
162where
163    Self: Sized,
164{
165    type Native: NativeWasmType;
167
168    fn from_native(native: Self::Native) -> Self;
170
171    fn to_native(self) -> Self::Native;
173}
174
175macro_rules! wasm_extern_type {
176    ($type:ty => $native_type:ty) => {
177        unsafe impl WasmExternType for $type {
178            type Native = $native_type;
179
180            fn from_native(native: Self::Native) -> Self {
181                native as _
182            }
183
184            fn to_native(self) -> Self::Native {
185                self as _
186            }
187        }
188    };
189}
190
191wasm_extern_type!(i8 => i32);
192wasm_extern_type!(u8 => i32);
193wasm_extern_type!(i16 => i32);
194wasm_extern_type!(u16 => i32);
195wasm_extern_type!(i32 => i32);
196wasm_extern_type!(u32 => i32);
197wasm_extern_type!(i64 => i64);
198wasm_extern_type!(u64 => i64);
199wasm_extern_type!(f32 => f32);
200wasm_extern_type!(f64 => f64);
201
202pub unsafe trait ValueType: Copy
230where
231    Self: Sized,
232{
233}
234
235macro_rules! convert_value_impl {
236    ($t:ty) => {
237        unsafe impl ValueType for $t {}
238    };
239    ( $($t:ty),* ) => {
240        $(
241            convert_value_impl!($t);
242        )*
243    };
244}
245
246convert_value_impl!(u8, i8, u16, i16, u32, i32, u64, i64, f32, f64);
247
248#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
250pub enum ElementType {
251    Anyfunc,
253}
254
255#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
258pub struct TableDescriptor {
259    pub element: ElementType,
261    pub minimum: u32,
263    pub maximum: Option<u32>,
265}
266
267impl TableDescriptor {
268    pub(crate) fn fits_in_imported(&self, imported: TableDescriptor) -> bool {
269        let imported_max = imported.maximum.unwrap_or(u32::max_value());
271        let self_max = self.maximum.unwrap_or(u32::max_value());
272        self.element == imported.element
273            && imported_max <= self_max
274            && self.minimum <= imported.minimum
275    }
276}
277
278#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
282pub enum Initializer {
283    Const(Value),
285    GetGlobal(ImportedGlobalIndex),
287}
288
289#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
291pub struct GlobalDescriptor {
292    pub mutable: bool,
294    pub ty: Type,
296}
297
298#[derive(Serialize, Deserialize, Debug, Clone)]
300pub struct GlobalInit {
301    pub desc: GlobalDescriptor,
303    pub init: Initializer,
305}
306
307#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
309pub struct MemoryDescriptor {
310    pub minimum: Pages,
312    pub maximum: Option<Pages>,
314    pub shared: bool,
316    pub memory_type: MemoryType,
318}
319
320impl MemoryDescriptor {
321    pub fn new(minimum: Pages, maximum: Option<Pages>, shared: bool) -> Result<Self, String> {
323        let memory_type = match (maximum.is_some(), shared) {
324            (true, true) => MemoryType::SharedStatic,
325            (true, false) => MemoryType::Static,
326            (false, false) => MemoryType::Dynamic,
327            (false, true) => {
328                return Err("Max number of pages is required for shared memory".to_string());
329            }
330        };
331        Ok(MemoryDescriptor {
332            minimum,
333            maximum,
334            shared,
335            memory_type,
336        })
337    }
338
339    pub fn memory_type(&self) -> MemoryType {
341        self.memory_type
342    }
343
344    pub(crate) fn fits_in_imported(&self, imported: MemoryDescriptor) -> bool {
345        let imported_max = imported.maximum.unwrap_or(Pages(65_536));
346        let self_max = self.maximum.unwrap_or(Pages(65_536));
347
348        self.shared == imported.shared
349            && imported_max <= self_max
350            && self.minimum <= imported.minimum
351    }
352}
353
354#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
357pub struct FuncSig {
358    params: Cow<'static, [Type]>,
359    returns: Cow<'static, [Type]>,
360}
361
362pub type FuncDescriptor = FuncSig;
364
365impl FuncSig {
366    pub fn new<Params, Returns>(params: Params, returns: Returns) -> Self
368    where
369        Params: Into<Cow<'static, [Type]>>,
370        Returns: Into<Cow<'static, [Type]>>,
371    {
372        Self {
373            params: params.into(),
374            returns: returns.into(),
375        }
376    }
377
378    pub fn params(&self) -> &[Type] {
380        &self.params
381    }
382
383    pub fn returns(&self) -> &[Type] {
385        &self.returns
386    }
387
388    pub fn check_param_value_types(&self, params: &[Value]) -> bool {
390        self.params.len() == params.len()
391            && self
392                .params
393                .iter()
394                .zip(params.iter().map(|val| val.ty()))
395                .all(|(t0, ref t1)| t0 == t1)
396    }
397}
398
399impl std::fmt::Display for FuncSig {
400    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
401        let params = self
402            .params
403            .iter()
404            .map(|p| p.to_string())
405            .collect::<Vec<_>>()
406            .join(", ");
407        let returns = self
408            .returns
409            .iter()
410            .map(|p| p.to_string())
411            .collect::<Vec<_>>()
412            .join(", ");
413        write!(f, "[{}] -> [{}]", params, returns)
414    }
415}
416
417pub trait LocalImport {
419    type Local: TypedIndex;
421    type Import: TypedIndex;
423}
424
425#[rustfmt::skip]
426macro_rules! define_map_index {
427    ($ty:ident) => {
428        #[derive(Serialize, Deserialize)]
430        #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
431        pub struct $ty (u32);
432        impl TypedIndex for $ty {
433            #[doc(hidden)]
434            fn new(index: usize) -> Self {
435                $ty (index as _)
436            }
437
438            #[doc(hidden)]
439            fn index(&self) -> usize {
440                self.0 as usize
441            }
442        }
443    };
444    ($($normal_ty:ident,)* | local: $($local_ty:ident,)* | imported: $($imported_ty:ident,)*) => {
445        $(
446            define_map_index!($normal_ty);
447            define_map_index!($local_ty);
448            define_map_index!($imported_ty);
449
450            impl LocalImport for $normal_ty {
451                type Local = $local_ty;
452                type Import = $imported_ty;
453            }
454        )*
455    };
456}
457
458#[rustfmt::skip]
459define_map_index![
460    FuncIndex, MemoryIndex, TableIndex, GlobalIndex,
461    | local: LocalFuncIndex, LocalMemoryIndex, LocalTableIndex, LocalGlobalIndex,
462    | imported: ImportedFuncIndex, ImportedMemoryIndex, ImportedTableIndex, ImportedGlobalIndex,
463];
464
465#[rustfmt::skip]
466macro_rules! define_local_or_import {
467    ($ty:ident, $local_ty:ident, $imported_ty:ident, $imports:ident) => {
468        impl $ty {
469            pub fn local_or_import(self, info: &ModuleInfo) -> LocalOrImport<$ty> {
471                if self.index() < info.$imports.len() {
472                    LocalOrImport::Import(<Self as LocalImport>::Import::new(self.index()))
473                } else {
474                    LocalOrImport::Local(<Self as LocalImport>::Local::new(self.index() - info.$imports.len()))
475                }
476            }
477        }
478
479        impl $local_ty {
480            pub fn convert_up(self, info: &ModuleInfo) -> $ty {
482                $ty ((self.index() + info.$imports.len()) as u32)
483            }
484        }
485
486        impl $imported_ty {
487            pub fn convert_up(self, _info: &ModuleInfo) -> $ty {
489                $ty (self.index() as u32)
490            }
491        }
492    };
493    ($(($ty:ident | ($local_ty:ident, $imported_ty:ident): $imports:ident),)*) => {
494        $(
495            define_local_or_import!($ty, $local_ty, $imported_ty, $imports);
496        )*
497    };
498}
499
500#[rustfmt::skip]
501define_local_or_import![
502    (FuncIndex | (LocalFuncIndex, ImportedFuncIndex): imported_functions),
503    (MemoryIndex | (LocalMemoryIndex, ImportedMemoryIndex): imported_memories),
504    (TableIndex | (LocalTableIndex, ImportedTableIndex): imported_tables),
505    (GlobalIndex | (LocalGlobalIndex, ImportedGlobalIndex): imported_globals),
506];
507
508#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Hash)]
510pub struct SigIndex(u32);
511impl TypedIndex for SigIndex {
512    #[doc(hidden)]
513    fn new(index: usize) -> Self {
514        SigIndex(index as _)
515    }
516
517    #[doc(hidden)]
518    fn index(&self) -> usize {
519        self.0 as usize
520    }
521}
522
523pub enum LocalOrImport<T>
525where
526    T: LocalImport,
527{
528    Local(T::Local),
530    Import(T::Import),
532}
533
534impl<T> LocalOrImport<T>
535where
536    T: LocalImport,
537{
538    pub fn local(self) -> Option<T::Local> {
540        match self {
541            LocalOrImport::Local(local) => Some(local),
542            LocalOrImport::Import(_) => None,
543        }
544    }
545
546    pub fn import(self) -> Option<T::Import> {
548        match self {
549            LocalOrImport::Import(import) => Some(import),
550            LocalOrImport::Local(_) => None,
551        }
552    }
553}
554
555#[derive(Debug, Clone, PartialEq, Eq)]
557pub enum ExternDescriptor {
558    Function(FuncDescriptor),
560    Global(GlobalDescriptor),
562    Memory(MemoryDescriptor),
564    Table(TableDescriptor),
566}
567
568impl From<FuncDescriptor> for ExternDescriptor {
569    fn from(other: FuncDescriptor) -> Self {
570        ExternDescriptor::Function(other)
571    }
572}
573impl From<&FuncDescriptor> for ExternDescriptor {
574    fn from(other: &FuncDescriptor) -> Self {
575        ExternDescriptor::Function(other.clone())
576    }
577}
578impl From<MemoryDescriptor> for ExternDescriptor {
579    fn from(other: MemoryDescriptor) -> Self {
580        ExternDescriptor::Memory(other)
581    }
582}
583impl From<&MemoryDescriptor> for ExternDescriptor {
584    fn from(other: &MemoryDescriptor) -> Self {
585        ExternDescriptor::Memory(*other)
586    }
587}
588
589impl From<TableDescriptor> for ExternDescriptor {
590    fn from(other: TableDescriptor) -> Self {
591        ExternDescriptor::Table(other)
592    }
593}
594impl From<&TableDescriptor> for ExternDescriptor {
595    fn from(other: &TableDescriptor) -> Self {
596        ExternDescriptor::Table(*other)
597    }
598}
599impl From<GlobalDescriptor> for ExternDescriptor {
600    fn from(other: GlobalDescriptor) -> Self {
601        ExternDescriptor::Global(other)
602    }
603}
604impl From<&GlobalDescriptor> for ExternDescriptor {
605    fn from(other: &GlobalDescriptor) -> Self {
606        ExternDescriptor::Global(*other)
607    }
608}
609
610#[derive(Debug, Clone, PartialEq, Eq)]
612pub struct ImportDescriptor {
613    pub namespace: String,
615    pub name: String,
617    pub ty: ExternDescriptor,
619}
620
621#[derive(Debug, Clone, PartialEq, Eq)]
623pub struct ExportDescriptor<'a> {
624    pub name: &'a str,
626    pub ty: ExternDescriptor,
628}
629
630#[cfg(test)]
631mod tests {
632    use crate::types::NativeWasmType;
633    use crate::types::WasmExternType;
634
635    #[test]
636    fn test_native_types_round_trip() {
637        assert_eq!(
638            42i32,
639            i32::from_native(i32::from_binary((42i32).to_native().to_binary()))
640        );
641
642        assert_eq!(
643            -42i32,
644            i32::from_native(i32::from_binary((-42i32).to_native().to_binary()))
645        );
646
647        use std::i64;
648        let xi64 = i64::MAX;
649        assert_eq!(
650            xi64,
651            i64::from_native(i64::from_binary((xi64).to_native().to_binary()))
652        );
653        let yi64 = i64::MIN;
654        assert_eq!(
655            yi64,
656            i64::from_native(i64::from_binary((yi64).to_native().to_binary()))
657        );
658
659        assert_eq!(
660            16.5f32,
661            f32::from_native(f32::from_binary((16.5f32).to_native().to_binary()))
662        );
663
664        assert_eq!(
665            -16.5f32,
666            f32::from_native(f32::from_binary((-16.5f32).to_native().to_binary()))
667        );
668
669        use std::f64;
670        let xf64: f64 = f64::MAX;
671        assert_eq!(
672            xf64,
673            f64::from_native(f64::from_binary((xf64).to_native().to_binary()))
674        );
675
676        let yf64: f64 = f64::MIN;
677        assert_eq!(
678            yf64,
679            f64::from_native(f64::from_binary((yf64).to_native().to_binary()))
680        );
681    }
682}