1use crate::indexes::{FunctionIndex, GlobalIndex};
2use crate::lib::std::borrow::ToOwned;
3use crate::lib::std::fmt;
4use crate::lib::std::format;
5use crate::lib::std::string::{String, ToString};
6use crate::lib::std::vec::Vec;
7use crate::units::Pages;
8
9use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize};
10#[cfg(feature = "enable-serde")]
11use serde::{Deserialize, Serialize};
12
13#[derive(Copy, Debug, Clone, Eq, PartialEq, Hash)]
19#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
20#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
21#[derive(RkyvSerialize, RkyvDeserialize, Archive)]
22#[rkyv(derive(Debug), compare(PartialEq))]
23#[repr(u8)]
24pub enum Type {
25 I32,
27 I64,
29 F32,
31 F64,
33 V128,
35 ExternRef, FuncRef,
39 ExceptionRef,
41}
42
43impl Type {
44 pub fn is_num(self) -> bool {
47 matches!(
48 self,
49 Self::I32 | Self::I64 | Self::F32 | Self::F64 | Self::V128
50 )
51 }
52
53 pub fn is_ref(self) -> bool {
55 matches!(self, Self::ExternRef | Self::FuncRef | Self::ExceptionRef)
56 }
57}
58
59impl fmt::Display for Type {
60 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
61 write!(f, "{self:?}")
62 }
63}
64
65#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
67#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
68#[derive(RkyvSerialize, RkyvDeserialize, Archive)]
69#[rkyv(derive(Debug), compare(PartialEq))]
70pub struct V128(pub(crate) [u8; 16]);
71
72#[cfg(feature = "artifact-size")]
73impl loupe::MemoryUsage for V128 {
74 fn size_of_val(&self, _tracker: &mut dyn loupe::MemoryUsageTracker) -> usize {
75 16 * 8
76 }
77}
78
79impl V128 {
80 pub fn bytes(&self) -> &[u8; 16] {
82 &self.0
83 }
84 pub fn iter(&self) -> impl Iterator<Item = &u8> {
86 self.0.iter()
87 }
88
89 pub fn to_vec(self) -> Vec<u8> {
91 self.0.to_vec()
92 }
93
94 pub fn as_slice(&self) -> &[u8] {
96 &self.0[..]
97 }
98}
99
100impl From<[u8; 16]> for V128 {
101 fn from(array: [u8; 16]) -> Self {
102 Self(array)
103 }
104}
105
106impl From<&[u8]> for V128 {
107 fn from(slice: &[u8]) -> Self {
108 assert_eq!(slice.len(), 16);
109 let mut buffer = [0; 16];
110 buffer.copy_from_slice(slice);
111 Self(buffer)
112 }
113}
114
115#[derive(Debug, Clone, PartialEq, Eq, Hash)]
123#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
124pub enum ExternType {
125 Function(FunctionType),
127 Global(GlobalType),
129 Table(TableType),
131 Memory(MemoryType),
133 Tag(TagType),
135}
136
137fn is_global_compatible(exported: GlobalType, imported: GlobalType) -> bool {
138 let GlobalType {
139 ty: exported_ty,
140 mutability: exported_mutability,
141 } = exported;
142 let GlobalType {
143 ty: imported_ty,
144 mutability: imported_mutability,
145 } = imported;
146
147 exported_ty == imported_ty && imported_mutability == exported_mutability
148}
149
150fn is_table_element_type_compatible(exported_type: Type, imported_type: Type) -> bool {
151 match exported_type {
152 Type::FuncRef => true,
153 _ => imported_type == exported_type,
154 }
155}
156
157fn is_table_compatible(
158 exported: &TableType,
159 imported: &TableType,
160 imported_runtime_size: Option<u32>,
161) -> bool {
162 let TableType {
163 ty: exported_ty,
164 minimum: exported_minimum,
165 maximum: exported_maximum,
166 } = exported;
167 let TableType {
168 ty: imported_ty,
169 minimum: imported_minimum,
170 maximum: imported_maximum,
171 } = imported;
172
173 is_table_element_type_compatible(*exported_ty, *imported_ty)
174 && *imported_minimum <= imported_runtime_size.unwrap_or(*exported_minimum)
175 && (imported_maximum.is_none()
176 || (!exported_maximum.is_none()
177 && imported_maximum.unwrap() >= exported_maximum.unwrap()))
178}
179
180fn is_memory_compatible(
181 exported: &MemoryType,
182 imported: &MemoryType,
183 imported_runtime_size: Option<u32>,
184) -> bool {
185 let MemoryType {
186 minimum: exported_minimum,
187 maximum: exported_maximum,
188 shared: exported_shared,
189 } = exported;
190 let MemoryType {
191 minimum: imported_minimum,
192 maximum: imported_maximum,
193 shared: imported_shared,
194 } = imported;
195
196 imported_minimum.0 <= imported_runtime_size.unwrap_or(exported_minimum.0)
197 && (imported_maximum.is_none()
198 || (!exported_maximum.is_none()
199 && imported_maximum.unwrap() >= exported_maximum.unwrap()))
200 && exported_shared == imported_shared
201}
202
203macro_rules! accessors {
204 ($(($variant:ident($ty:ty) $get:ident $unwrap:ident))*) => ($(
205 pub fn $get(&self) -> Option<&$ty> {
208 if let Self::$variant(e) = self {
209 Some(e)
210 } else {
211 None
212 }
213 }
214
215 pub fn $unwrap(&self) -> &$ty {
222 self.$get().expect(concat!("expected ", stringify!($ty)))
223 }
224 )*)
225}
226
227impl ExternType {
228 accessors! {
229 (Function(FunctionType) func unwrap_func)
230 (Global(GlobalType) global unwrap_global)
231 (Table(TableType) table unwrap_table)
232 (Memory(MemoryType) memory unwrap_memory)
233 }
234 pub fn is_compatible_with(&self, other: &Self, runtime_size: Option<u32>) -> bool {
236 match (self, other) {
237 (Self::Function(a), Self::Function(b)) => a == b,
238 (Self::Global(a), Self::Global(b)) => is_global_compatible(*a, *b),
239 (Self::Table(a), Self::Table(b)) => is_table_compatible(a, b, runtime_size),
240 (Self::Memory(a), Self::Memory(b)) => is_memory_compatible(a, b, runtime_size),
241 (Self::Tag(a), Self::Tag(b)) => a == b,
242 _ => false,
244 }
245 }
246}
247
248#[derive(Debug, Clone, PartialEq, Eq, Hash)]
255#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
256#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
257#[derive(RkyvSerialize, RkyvDeserialize, Archive)]
258#[rkyv(derive(Debug))]
259pub struct FunctionType {
260 params: Box<[Type]>,
262 results: Box<[Type]>,
264}
265
266impl FunctionType {
267 pub fn new<Params, Returns>(params: Params, returns: Returns) -> Self
269 where
270 Params: Into<Box<[Type]>>,
271 Returns: Into<Box<[Type]>>,
272 {
273 Self {
274 params: params.into(),
275 results: returns.into(),
276 }
277 }
278
279 pub fn params(&self) -> &[Type] {
281 &self.params
282 }
283
284 pub fn results(&self) -> &[Type] {
286 &self.results
287 }
288}
289
290impl fmt::Display for FunctionType {
291 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
292 let params = self
293 .params
294 .iter()
295 .map(|p| format!("{p:?}"))
296 .collect::<Vec<_>>()
297 .join(", ");
298 let results = self
299 .results
300 .iter()
301 .map(|p| format!("{p:?}"))
302 .collect::<Vec<_>>()
303 .join(", ");
304 write!(f, "[{params}] -> [{results}]")
305 }
306}
307
308macro_rules! implement_from_pair_to_functiontype {
311 ($($N:literal,$M:literal)+) => {
312 $(
313 impl From<([Type; $N], [Type; $M])> for FunctionType {
314 fn from(pair: ([Type; $N], [Type; $M])) -> Self {
315 Self::new(pair.0, pair.1)
316 }
317 }
318 )+
319 }
320}
321
322implement_from_pair_to_functiontype! {
323 0,0 0,1 0,2 0,3 0,4 0,5 0,6 0,7 0,8 0,9
324 1,0 1,1 1,2 1,3 1,4 1,5 1,6 1,7 1,8 1,9
325 2,0 2,1 2,2 2,3 2,4 2,5 2,6 2,7 2,8 2,9
326 3,0 3,1 3,2 3,3 3,4 3,5 3,6 3,7 3,8 3,9
327 4,0 4,1 4,2 4,3 4,4 4,5 4,6 4,7 4,8 4,9
328 5,0 5,1 5,2 5,3 5,4 5,5 5,6 5,7 5,8 5,9
329 6,0 6,1 6,2 6,3 6,4 6,5 6,6 6,7 6,8 6,9
330 7,0 7,1 7,2 7,3 7,4 7,5 7,6 7,7 7,8 7,9
331 8,0 8,1 8,2 8,3 8,4 8,5 8,6 8,7 8,8 8,9
332 9,0 9,1 9,2 9,3 9,4 9,5 9,6 9,7 9,8 9,9
333}
334
335impl From<&Self> for FunctionType {
336 fn from(as_ref: &Self) -> Self {
337 as_ref.clone()
338 }
339}
340
341#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, RkyvSerialize, RkyvDeserialize, Archive)]
343#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
344#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
345#[rkyv(derive(Debug), compare(PartialOrd, PartialEq))]
346#[repr(u8)]
347pub enum Mutability {
348 Const,
350 Var,
352}
353
354impl Mutability {
355 pub fn is_mutable(self) -> bool {
357 self.into()
358 }
359}
360
361impl From<bool> for Mutability {
362 fn from(value: bool) -> Self {
363 if value {
364 Self::Var
365 } else {
366 Self::Const
367 }
368 }
369}
370
371impl From<Mutability> for bool {
372 fn from(value: Mutability) -> Self {
373 match value {
374 Mutability::Var => true,
375 Mutability::Const => false,
376 }
377 }
378}
379
380#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, RkyvSerialize, RkyvDeserialize, Archive)]
382#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
383#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
384#[rkyv(derive(Debug), compare(PartialEq))]
385pub struct GlobalType {
386 pub ty: Type,
388 pub mutability: Mutability,
390}
391
392impl GlobalType {
400 pub fn new(ty: Type, mutability: Mutability) -> Self {
411 Self { ty, mutability }
412 }
413}
414
415impl fmt::Display for GlobalType {
416 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
417 let mutability = match self.mutability {
418 Mutability::Const => "constant",
419 Mutability::Var => "mutable",
420 };
421 write!(f, "{} ({})", self.ty, mutability)
422 }
423}
424
425#[derive(Debug, Clone, Copy, PartialEq, RkyvSerialize, RkyvDeserialize, Archive)]
427#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
428#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
429#[rkyv(derive(Debug), compare(PartialEq))]
430#[repr(u8)]
431pub enum GlobalInit {
432 I32Const(i32),
434 I64Const(i64),
436 F32Const(f32),
438 F64Const(f64),
440 V128Const(V128),
442 GetGlobal(GlobalIndex),
444 RefNullConst,
449 RefFunc(FunctionIndex),
451}
452
453#[derive(Debug, Clone, PartialEq, Eq, Hash)]
459#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
460#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
461#[derive(RkyvSerialize, RkyvDeserialize, Archive)]
462#[rkyv(derive(Debug))]
463pub enum TagKind {
464 Exception,
466}
467
468#[derive(Debug, Clone, PartialEq, Eq, Hash)]
471#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
472#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
473#[derive(RkyvSerialize, RkyvDeserialize, Archive)]
474#[rkyv(derive(Debug))]
475pub struct TagType {
476 pub kind: TagKind,
478 pub ty: FunctionType,
480}
481
482impl TagType {
483 pub fn new<Params, Returns>(kind: TagKind, params: Params, returns: Returns) -> Self
485 where
486 Params: Into<Box<[Type]>>,
487 Returns: Into<Box<[Type]>>,
488 {
489 let ty = FunctionType::new(params.into(), returns.into());
490
491 Self::from_fn_type(kind, ty)
492 }
493
494 pub fn results(&self) -> &[Type] {
496 self.ty.results()
497 }
498
499 pub fn params(&self) -> &[Type] {
501 self.ty.params()
502 }
503
504 pub fn from_fn_type(kind: TagKind, ty: FunctionType) -> Self {
506 Self { kind, ty }
507 }
508}
509
510impl fmt::Display for TagType {
511 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
512 write!(
513 f,
514 "({:?}) {:?} -> {:?}",
515 self.kind,
516 self.params(),
517 self.results()
518 )
519 }
520}
521
522#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
530#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
531#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
532#[derive(RkyvSerialize, RkyvDeserialize, Archive)]
533#[rkyv(derive(Debug))]
534pub struct TableType {
535 pub ty: Type,
537 pub minimum: u32,
539 pub maximum: Option<u32>,
541}
542
543impl TableType {
544 pub fn new(ty: Type, minimum: u32, maximum: Option<u32>) -> Self {
547 Self {
548 ty,
549 minimum,
550 maximum,
551 }
552 }
553}
554
555impl fmt::Display for TableType {
556 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
557 if let Some(maximum) = self.maximum {
558 write!(f, "{} ({}..{})", self.ty, self.minimum, maximum)
559 } else {
560 write!(f, "{} ({}..)", self.ty, self.minimum)
561 }
562 }
563}
564
565#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
572#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
573#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
574#[derive(RkyvSerialize, RkyvDeserialize, Archive)]
575#[rkyv(derive(Debug))]
576pub struct MemoryType {
577 pub minimum: Pages,
579 pub maximum: Option<Pages>,
581 pub shared: bool,
583}
584
585impl MemoryType {
586 pub fn new<IntoPages>(minimum: IntoPages, maximum: Option<IntoPages>, shared: bool) -> Self
589 where
590 IntoPages: Into<Pages>,
591 {
592 Self {
593 minimum: minimum.into(),
594 maximum: maximum.map(Into::into),
595 shared,
596 }
597 }
598}
599
600impl fmt::Display for MemoryType {
601 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
602 let shared = if self.shared { "shared" } else { "not shared" };
603 if let Some(maximum) = self.maximum {
604 write!(f, "{} ({:?}..{:?})", shared, self.minimum, maximum)
605 } else {
606 write!(f, "{} ({:?}..)", shared, self.minimum)
607 }
608 }
609}
610
611#[derive(Debug, Clone, PartialEq, Eq, Hash)]
620#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
621pub struct ImportType<T = ExternType> {
622 module: String,
623 name: String,
624 ty: T,
625}
626
627impl<T> ImportType<T> {
628 pub fn new(module: &str, name: &str, ty: T) -> Self {
631 Self {
632 module: module.to_owned(),
633 name: name.to_owned(),
634 ty,
635 }
636 }
637
638 pub fn module(&self) -> &str {
640 &self.module
641 }
642
643 pub fn name(&self) -> &str {
646 &self.name
647 }
648
649 pub fn ty(&self) -> &T {
651 &self.ty
652 }
653}
654
655#[derive(Debug, Clone, PartialEq, Eq, Hash)]
667#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
668pub struct ExportType<T = ExternType> {
669 name: String,
670 ty: T,
671}
672
673impl<T> ExportType<T> {
674 pub fn new(name: &str, ty: T) -> Self {
677 Self {
678 name: name.to_string(),
679 ty,
680 }
681 }
682
683 pub fn name(&self) -> &str {
685 &self.name
686 }
687
688 pub fn ty(&self) -> &T {
690 &self.ty
691 }
692}
693
694#[cfg(test)]
695mod tests {
696 use super::*;
697
698 const VOID_TO_VOID: ([Type; 0], [Type; 0]) = ([], []);
699 const I32_I32_TO_VOID: ([Type; 2], [Type; 0]) = ([Type::I32, Type::I32], []);
700 const V128_I64_TO_I32: ([Type; 2], [Type; 1]) = ([Type::V128, Type::I64], [Type::I32]);
701 const NINE_V128_TO_NINE_I32: ([Type; 9], [Type; 9]) = ([Type::V128; 9], [Type::I32; 9]);
702
703 #[test]
704 fn convert_tuple_to_functiontype() {
705 let ty: FunctionType = VOID_TO_VOID.into();
706 assert_eq!(ty.params().len(), 0);
707 assert_eq!(ty.results().len(), 0);
708
709 let ty: FunctionType = I32_I32_TO_VOID.into();
710 assert_eq!(ty.params().len(), 2);
711 assert_eq!(ty.params()[0], Type::I32);
712 assert_eq!(ty.params()[1], Type::I32);
713 assert_eq!(ty.results().len(), 0);
714
715 let ty: FunctionType = V128_I64_TO_I32.into();
716 assert_eq!(ty.params().len(), 2);
717 assert_eq!(ty.params()[0], Type::V128);
718 assert_eq!(ty.params()[1], Type::I64);
719 assert_eq!(ty.results().len(), 1);
720 assert_eq!(ty.results()[0], Type::I32);
721
722 let ty: FunctionType = NINE_V128_TO_NINE_I32.into();
723 assert_eq!(ty.params().len(), 9);
724 assert_eq!(ty.results().len(), 9);
725 }
726}