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 params: Box<[Type]>,
480}
481
482impl TagType {
483 pub fn new<Params>(kind: TagKind, params: Params) -> Self
485 where
486 Params: Into<Box<[Type]>>,
487 {
488 Self {
489 kind,
490 params: params.into(),
491 }
492 }
493
494 pub fn params(&self) -> &[Type] {
496 &self.params
497 }
498
499 pub fn from_fn_type(kind: TagKind, ty: FunctionType) -> Self {
501 Self {
502 kind,
503 params: ty.params().into(),
504 }
505 }
506}
507
508impl fmt::Display for TagType {
509 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
510 write!(f, "({:?}) {:?}", self.kind, self.params(),)
511 }
512}
513
514#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
522#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
523#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
524#[derive(RkyvSerialize, RkyvDeserialize, Archive)]
525#[rkyv(derive(Debug))]
526pub struct TableType {
527 pub ty: Type,
529 pub minimum: u32,
531 pub maximum: Option<u32>,
533}
534
535impl TableType {
536 pub fn new(ty: Type, minimum: u32, maximum: Option<u32>) -> Self {
539 Self {
540 ty,
541 minimum,
542 maximum,
543 }
544 }
545}
546
547impl fmt::Display for TableType {
548 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
549 if let Some(maximum) = self.maximum {
550 write!(f, "{} ({}..{})", self.ty, self.minimum, maximum)
551 } else {
552 write!(f, "{} ({}..)", self.ty, self.minimum)
553 }
554 }
555}
556
557#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
564#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
565#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
566#[derive(RkyvSerialize, RkyvDeserialize, Archive)]
567#[rkyv(derive(Debug))]
568pub struct MemoryType {
569 pub minimum: Pages,
571 pub maximum: Option<Pages>,
573 pub shared: bool,
575}
576
577impl MemoryType {
578 pub fn new<IntoPages>(minimum: IntoPages, maximum: Option<IntoPages>, shared: bool) -> Self
581 where
582 IntoPages: Into<Pages>,
583 {
584 Self {
585 minimum: minimum.into(),
586 maximum: maximum.map(Into::into),
587 shared,
588 }
589 }
590}
591
592impl fmt::Display for MemoryType {
593 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
594 let shared = if self.shared { "shared" } else { "not shared" };
595 if let Some(maximum) = self.maximum {
596 write!(f, "{} ({:?}..{:?})", shared, self.minimum, maximum)
597 } else {
598 write!(f, "{} ({:?}..)", shared, self.minimum)
599 }
600 }
601}
602
603#[derive(Debug, Clone, PartialEq, Eq, Hash)]
612#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
613pub struct ImportType<T = ExternType> {
614 module: String,
615 name: String,
616 ty: T,
617}
618
619impl<T> ImportType<T> {
620 pub fn new(module: &str, name: &str, ty: T) -> Self {
623 Self {
624 module: module.to_owned(),
625 name: name.to_owned(),
626 ty,
627 }
628 }
629
630 pub fn module(&self) -> &str {
632 &self.module
633 }
634
635 pub fn name(&self) -> &str {
638 &self.name
639 }
640
641 pub fn ty(&self) -> &T {
643 &self.ty
644 }
645}
646
647#[derive(Debug, Clone, PartialEq, Eq, Hash)]
659#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
660pub struct ExportType<T = ExternType> {
661 name: String,
662 ty: T,
663}
664
665impl<T> ExportType<T> {
666 pub fn new(name: &str, ty: T) -> Self {
669 Self {
670 name: name.to_string(),
671 ty,
672 }
673 }
674
675 pub fn name(&self) -> &str {
677 &self.name
678 }
679
680 pub fn ty(&self) -> &T {
682 &self.ty
683 }
684}
685
686#[cfg(test)]
687mod tests {
688 use super::*;
689
690 const VOID_TO_VOID: ([Type; 0], [Type; 0]) = ([], []);
691 const I32_I32_TO_VOID: ([Type; 2], [Type; 0]) = ([Type::I32, Type::I32], []);
692 const V128_I64_TO_I32: ([Type; 2], [Type; 1]) = ([Type::V128, Type::I64], [Type::I32]);
693 const NINE_V128_TO_NINE_I32: ([Type; 9], [Type; 9]) = ([Type::V128; 9], [Type::I32; 9]);
694
695 #[test]
696 fn convert_tuple_to_functiontype() {
697 let ty: FunctionType = VOID_TO_VOID.into();
698 assert_eq!(ty.params().len(), 0);
699 assert_eq!(ty.results().len(), 0);
700
701 let ty: FunctionType = I32_I32_TO_VOID.into();
702 assert_eq!(ty.params().len(), 2);
703 assert_eq!(ty.params()[0], Type::I32);
704 assert_eq!(ty.params()[1], Type::I32);
705 assert_eq!(ty.results().len(), 0);
706
707 let ty: FunctionType = V128_I64_TO_I32.into();
708 assert_eq!(ty.params().len(), 2);
709 assert_eq!(ty.params()[0], Type::V128);
710 assert_eq!(ty.params()[1], Type::I64);
711 assert_eq!(ty.results().len(), 1);
712 assert_eq!(ty.results()[0], Type::I32);
713
714 let ty: FunctionType = NINE_V128_TO_NINE_I32.into();
715 assert_eq!(ty.params().len(), 9);
716 assert_eq!(ty.results().len(), 9);
717 }
718}