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}