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}
40
41impl Type {
42 pub fn is_num(self) -> bool {
45 matches!(
46 self,
47 Self::I32 | Self::I64 | Self::F32 | Self::F64 | Self::V128
48 )
49 }
50
51 pub fn is_ref(self) -> bool {
53 matches!(self, Self::ExternRef | Self::FuncRef)
54 }
55}
56
57impl fmt::Display for Type {
58 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
59 write!(f, "{:?}", self)
60 }
61}
62
63#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
65#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
66#[derive(RkyvSerialize, RkyvDeserialize, Archive)]
67#[rkyv(derive(Debug), compare(PartialEq))]
68pub struct V128(pub(crate) [u8; 16]);
69
70#[cfg(feature = "artifact-size")]
71impl loupe::MemoryUsage for V128 {
72 fn size_of_val(&self, _tracker: &mut dyn loupe::MemoryUsageTracker) -> usize {
73 16 * 8
74 }
75}
76
77impl V128 {
78 pub fn bytes(&self) -> &[u8; 16] {
80 &self.0
81 }
82 pub fn iter(&self) -> impl Iterator<Item = &u8> {
84 self.0.iter()
85 }
86
87 pub fn to_vec(self) -> Vec<u8> {
89 self.0.to_vec()
90 }
91
92 pub fn as_slice(&self) -> &[u8] {
94 &self.0[..]
95 }
96}
97
98impl From<[u8; 16]> for V128 {
99 fn from(array: [u8; 16]) -> Self {
100 Self(array)
101 }
102}
103
104impl From<&[u8]> for V128 {
105 fn from(slice: &[u8]) -> Self {
106 assert_eq!(slice.len(), 16);
107 let mut buffer = [0; 16];
108 buffer.copy_from_slice(slice);
109 Self(buffer)
110 }
111}
112
113#[derive(Debug, Clone, PartialEq, Eq, Hash)]
121#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
122pub enum ExternType {
123 Function(FunctionType),
125 Global(GlobalType),
127 Table(TableType),
129 Memory(MemoryType),
131}
132
133fn is_global_compatible(exported: GlobalType, imported: GlobalType) -> bool {
134 let GlobalType {
135 ty: exported_ty,
136 mutability: exported_mutability,
137 } = exported;
138 let GlobalType {
139 ty: imported_ty,
140 mutability: imported_mutability,
141 } = imported;
142
143 exported_ty == imported_ty && imported_mutability == exported_mutability
144}
145
146fn is_table_element_type_compatible(exported_type: Type, imported_type: Type) -> bool {
147 match exported_type {
148 Type::FuncRef => true,
149 _ => imported_type == exported_type,
150 }
151}
152
153fn is_table_compatible(
154 exported: &TableType,
155 imported: &TableType,
156 imported_runtime_size: Option<u32>,
157) -> bool {
158 let TableType {
159 ty: exported_ty,
160 minimum: exported_minimum,
161 maximum: exported_maximum,
162 } = exported;
163 let TableType {
164 ty: imported_ty,
165 minimum: imported_minimum,
166 maximum: imported_maximum,
167 } = imported;
168
169 is_table_element_type_compatible(*exported_ty, *imported_ty)
170 && *imported_minimum <= imported_runtime_size.unwrap_or(*exported_minimum)
171 && (imported_maximum.is_none()
172 || (!exported_maximum.is_none()
173 && imported_maximum.unwrap() >= exported_maximum.unwrap()))
174}
175
176fn is_memory_compatible(
177 exported: &MemoryType,
178 imported: &MemoryType,
179 imported_runtime_size: Option<u32>,
180) -> bool {
181 let MemoryType {
182 minimum: exported_minimum,
183 maximum: exported_maximum,
184 shared: exported_shared,
185 } = exported;
186 let MemoryType {
187 minimum: imported_minimum,
188 maximum: imported_maximum,
189 shared: imported_shared,
190 } = imported;
191
192 imported_minimum.0 <= imported_runtime_size.unwrap_or(exported_minimum.0)
193 && (imported_maximum.is_none()
194 || (!exported_maximum.is_none()
195 && imported_maximum.unwrap() >= exported_maximum.unwrap()))
196 && exported_shared == imported_shared
197}
198
199macro_rules! accessors {
200 ($(($variant:ident($ty:ty) $get:ident $unwrap:ident))*) => ($(
201 pub fn $get(&self) -> Option<&$ty> {
204 if let Self::$variant(e) = self {
205 Some(e)
206 } else {
207 None
208 }
209 }
210
211 pub fn $unwrap(&self) -> &$ty {
218 self.$get().expect(concat!("expected ", stringify!($ty)))
219 }
220 )*)
221}
222
223impl ExternType {
224 accessors! {
225 (Function(FunctionType) func unwrap_func)
226 (Global(GlobalType) global unwrap_global)
227 (Table(TableType) table unwrap_table)
228 (Memory(MemoryType) memory unwrap_memory)
229 }
230 pub fn is_compatible_with(&self, other: &Self, runtime_size: Option<u32>) -> bool {
232 match (self, other) {
233 (Self::Function(a), Self::Function(b)) => a == b,
234 (Self::Global(a), Self::Global(b)) => is_global_compatible(*a, *b),
235 (Self::Table(a), Self::Table(b)) => is_table_compatible(a, b, runtime_size),
236 (Self::Memory(a), Self::Memory(b)) => is_memory_compatible(a, b, runtime_size),
237 _ => false,
239 }
240 }
241}
242
243#[derive(Debug, Clone, PartialEq, Eq, Hash)]
250#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
251#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
252#[derive(RkyvSerialize, RkyvDeserialize, Archive)]
253#[rkyv(derive(Debug))]
254pub struct FunctionType {
255 params: Box<[Type]>,
257 results: Box<[Type]>,
259}
260
261impl FunctionType {
262 pub fn new<Params, Returns>(params: Params, returns: Returns) -> Self
264 where
265 Params: Into<Box<[Type]>>,
266 Returns: Into<Box<[Type]>>,
267 {
268 Self {
269 params: params.into(),
270 results: returns.into(),
271 }
272 }
273
274 pub fn params(&self) -> &[Type] {
276 &self.params
277 }
278
279 pub fn results(&self) -> &[Type] {
281 &self.results
282 }
283}
284
285impl fmt::Display for FunctionType {
286 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
287 let params = self
288 .params
289 .iter()
290 .map(|p| format!("{:?}", p))
291 .collect::<Vec<_>>()
292 .join(", ");
293 let results = self
294 .results
295 .iter()
296 .map(|p| format!("{:?}", p))
297 .collect::<Vec<_>>()
298 .join(", ");
299 write!(f, "[{}] -> [{}]", params, results)
300 }
301}
302
303macro_rules! implement_from_pair_to_functiontype {
306 ($($N:literal,$M:literal)+) => {
307 $(
308 impl From<([Type; $N], [Type; $M])> for FunctionType {
309 fn from(pair: ([Type; $N], [Type; $M])) -> Self {
310 Self::new(pair.0, pair.1)
311 }
312 }
313 )+
314 }
315}
316
317implement_from_pair_to_functiontype! {
318 0,0 0,1 0,2 0,3 0,4 0,5 0,6 0,7 0,8 0,9
319 1,0 1,1 1,2 1,3 1,4 1,5 1,6 1,7 1,8 1,9
320 2,0 2,1 2,2 2,3 2,4 2,5 2,6 2,7 2,8 2,9
321 3,0 3,1 3,2 3,3 3,4 3,5 3,6 3,7 3,8 3,9
322 4,0 4,1 4,2 4,3 4,4 4,5 4,6 4,7 4,8 4,9
323 5,0 5,1 5,2 5,3 5,4 5,5 5,6 5,7 5,8 5,9
324 6,0 6,1 6,2 6,3 6,4 6,5 6,6 6,7 6,8 6,9
325 7,0 7,1 7,2 7,3 7,4 7,5 7,6 7,7 7,8 7,9
326 8,0 8,1 8,2 8,3 8,4 8,5 8,6 8,7 8,8 8,9
327 9,0 9,1 9,2 9,3 9,4 9,5 9,6 9,7 9,8 9,9
328}
329
330impl From<&Self> for FunctionType {
331 fn from(as_ref: &Self) -> Self {
332 as_ref.clone()
333 }
334}
335
336#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, RkyvSerialize, RkyvDeserialize, Archive)]
338#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
339#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
340#[rkyv(derive(Debug), compare(PartialOrd, PartialEq))]
341#[repr(u8)]
342pub enum Mutability {
343 Const,
345 Var,
347}
348
349impl Mutability {
350 pub fn is_mutable(self) -> bool {
352 self.into()
353 }
354}
355
356impl From<bool> for Mutability {
357 fn from(value: bool) -> Self {
358 if value {
359 Self::Var
360 } else {
361 Self::Const
362 }
363 }
364}
365
366impl From<Mutability> for bool {
367 fn from(value: Mutability) -> Self {
368 match value {
369 Mutability::Var => true,
370 Mutability::Const => false,
371 }
372 }
373}
374
375#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, RkyvSerialize, RkyvDeserialize, Archive)]
377#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
378#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
379#[rkyv(derive(Debug), compare(PartialEq))]
380pub struct GlobalType {
381 pub ty: Type,
383 pub mutability: Mutability,
385}
386
387impl GlobalType {
395 pub fn new(ty: Type, mutability: Mutability) -> Self {
406 Self { ty, mutability }
407 }
408}
409
410impl fmt::Display for GlobalType {
411 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
412 let mutability = match self.mutability {
413 Mutability::Const => "constant",
414 Mutability::Var => "mutable",
415 };
416 write!(f, "{} ({})", self.ty, mutability)
417 }
418}
419
420#[derive(Debug, Clone, Copy, PartialEq, RkyvSerialize, RkyvDeserialize, Archive)]
422#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
423#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
424#[rkyv(derive(Debug), compare(PartialEq))]
425#[repr(u8)]
426pub enum GlobalInit {
427 I32Const(i32),
429 I64Const(i64),
431 F32Const(f32),
433 F64Const(f64),
435 V128Const(V128),
437 GetGlobal(GlobalIndex),
439 RefNullConst,
444 RefFunc(FunctionIndex),
446}
447
448#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
456#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
457#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
458#[derive(RkyvSerialize, RkyvDeserialize, Archive)]
459#[rkyv(derive(Debug))]
460pub struct TableType {
461 pub ty: Type,
463 pub minimum: u32,
465 pub maximum: Option<u32>,
467}
468
469impl TableType {
470 pub fn new(ty: Type, minimum: u32, maximum: Option<u32>) -> Self {
473 Self {
474 ty,
475 minimum,
476 maximum,
477 }
478 }
479}
480
481impl fmt::Display for TableType {
482 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
483 if let Some(maximum) = self.maximum {
484 write!(f, "{} ({}..{})", self.ty, self.minimum, maximum)
485 } else {
486 write!(f, "{} ({}..)", self.ty, self.minimum)
487 }
488 }
489}
490
491#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
498#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
499#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
500#[derive(RkyvSerialize, RkyvDeserialize, Archive)]
501#[rkyv(derive(Debug))]
502pub struct MemoryType {
503 pub minimum: Pages,
505 pub maximum: Option<Pages>,
507 pub shared: bool,
509}
510
511impl MemoryType {
512 pub fn new<IntoPages>(minimum: IntoPages, maximum: Option<IntoPages>, shared: bool) -> Self
515 where
516 IntoPages: Into<Pages>,
517 {
518 Self {
519 minimum: minimum.into(),
520 maximum: maximum.map(Into::into),
521 shared,
522 }
523 }
524}
525
526impl fmt::Display for MemoryType {
527 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
528 let shared = if self.shared { "shared" } else { "not shared" };
529 if let Some(maximum) = self.maximum {
530 write!(f, "{} ({:?}..{:?})", shared, self.minimum, maximum)
531 } else {
532 write!(f, "{} ({:?}..)", shared, self.minimum)
533 }
534 }
535}
536
537#[derive(Debug, Clone, PartialEq, Eq, Hash)]
546#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
547pub struct ImportType<T = ExternType> {
548 module: String,
549 name: String,
550 ty: T,
551}
552
553impl<T> ImportType<T> {
554 pub fn new(module: &str, name: &str, ty: T) -> Self {
557 Self {
558 module: module.to_owned(),
559 name: name.to_owned(),
560 ty,
561 }
562 }
563
564 pub fn module(&self) -> &str {
566 &self.module
567 }
568
569 pub fn name(&self) -> &str {
572 &self.name
573 }
574
575 pub fn ty(&self) -> &T {
577 &self.ty
578 }
579}
580
581#[derive(Debug, Clone, PartialEq, Eq, Hash)]
593#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
594pub struct ExportType<T = ExternType> {
595 name: String,
596 ty: T,
597}
598
599impl<T> ExportType<T> {
600 pub fn new(name: &str, ty: T) -> Self {
603 Self {
604 name: name.to_string(),
605 ty,
606 }
607 }
608
609 pub fn name(&self) -> &str {
611 &self.name
612 }
613
614 pub fn ty(&self) -> &T {
616 &self.ty
617 }
618}
619
620#[cfg(test)]
621mod tests {
622 use super::*;
623
624 const VOID_TO_VOID: ([Type; 0], [Type; 0]) = ([], []);
625 const I32_I32_TO_VOID: ([Type; 2], [Type; 0]) = ([Type::I32, Type::I32], []);
626 const V128_I64_TO_I32: ([Type; 2], [Type; 1]) = ([Type::V128, Type::I64], [Type::I32]);
627 const NINE_V128_TO_NINE_I32: ([Type; 9], [Type; 9]) = ([Type::V128; 9], [Type::I32; 9]);
628
629 #[test]
630 fn convert_tuple_to_functiontype() {
631 let ty: FunctionType = VOID_TO_VOID.into();
632 assert_eq!(ty.params().len(), 0);
633 assert_eq!(ty.results().len(), 0);
634
635 let ty: FunctionType = I32_I32_TO_VOID.into();
636 assert_eq!(ty.params().len(), 2);
637 assert_eq!(ty.params()[0], Type::I32);
638 assert_eq!(ty.params()[1], Type::I32);
639 assert_eq!(ty.results().len(), 0);
640
641 let ty: FunctionType = V128_I64_TO_I32.into();
642 assert_eq!(ty.params().len(), 2);
643 assert_eq!(ty.params()[0], Type::V128);
644 assert_eq!(ty.params()[1], Type::I64);
645 assert_eq!(ty.results().len(), 1);
646 assert_eq!(ty.results()[0], Type::I32);
647
648 let ty: FunctionType = NINE_V128_TO_NINE_I32.into();
649 assert_eq!(ty.params().len(), 9);
650 assert_eq!(ty.results().len(), 9);
651 }
652}