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 bytecheck::CheckBytes;
10use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize};
11#[cfg(feature = "enable-serde")]
12use serde::{Deserialize, Serialize};
13
14#[derive(Copy, Debug, Clone, Eq, PartialEq, Hash)]
20#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
21#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
22#[derive(RkyvSerialize, RkyvDeserialize, Archive, rkyv::CheckBytes)]
23#[archive(as = "Self")]
24#[repr(u8)]
25pub enum Type {
26 I32,
28 I64,
30 F32,
32 F64,
34 V128,
36 ExternRef, FuncRef,
40}
41
42impl Type {
43 pub fn is_num(self) -> bool {
46 matches!(
47 self,
48 Self::I32 | Self::I64 | Self::F32 | Self::F64 | Self::V128
49 )
50 }
51
52 pub fn is_ref(self) -> bool {
54 matches!(self, Self::ExternRef | Self::FuncRef)
55 }
56}
57
58impl fmt::Display for Type {
59 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
60 write!(f, "{:?}", self)
61 }
62}
63
64#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, CheckBytes)]
66#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
67#[derive(RkyvSerialize, RkyvDeserialize, Archive)]
68#[archive(as = "Self")]
69pub struct V128(pub(crate) [u8; 16]);
70
71#[cfg(feature = "artifact-size")]
72impl loupe::MemoryUsage for V128 {
73 fn size_of_val(&self, _tracker: &mut dyn loupe::MemoryUsageTracker) -> usize {
74 16 * 8
75 }
76}
77
78impl V128 {
79 pub fn bytes(&self) -> &[u8; 16] {
81 &self.0
82 }
83 pub fn iter(&self) -> impl Iterator<Item = &u8> {
85 self.0.iter()
86 }
87
88 pub fn to_vec(self) -> Vec<u8> {
90 self.0.to_vec()
91 }
92
93 pub fn as_slice(&self) -> &[u8] {
95 &self.0[..]
96 }
97}
98
99impl From<[u8; 16]> for V128 {
100 fn from(array: [u8; 16]) -> Self {
101 Self(array)
102 }
103}
104
105impl From<&[u8]> for V128 {
106 fn from(slice: &[u8]) -> Self {
107 assert_eq!(slice.len(), 16);
108 let mut buffer = [0; 16];
109 buffer.copy_from_slice(slice);
110 Self(buffer)
111 }
112}
113
114#[derive(Debug, Clone, PartialEq, Eq, Hash)]
122#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
123pub enum ExternType {
124 Function(FunctionType),
126 Global(GlobalType),
128 Table(TableType),
130 Memory(MemoryType),
132}
133
134fn is_global_compatible(exported: GlobalType, imported: GlobalType) -> bool {
135 let GlobalType {
136 ty: exported_ty,
137 mutability: exported_mutability,
138 } = exported;
139 let GlobalType {
140 ty: imported_ty,
141 mutability: imported_mutability,
142 } = imported;
143
144 exported_ty == imported_ty && imported_mutability == exported_mutability
145}
146
147fn is_table_element_type_compatible(exported_type: Type, imported_type: Type) -> bool {
148 match exported_type {
149 Type::FuncRef => true,
150 _ => imported_type == exported_type,
151 }
152}
153
154fn is_table_compatible(
155 exported: &TableType,
156 imported: &TableType,
157 imported_runtime_size: Option<u32>,
158) -> bool {
159 let TableType {
160 ty: exported_ty,
161 minimum: exported_minimum,
162 maximum: exported_maximum,
163 } = exported;
164 let TableType {
165 ty: imported_ty,
166 minimum: imported_minimum,
167 maximum: imported_maximum,
168 } = imported;
169
170 is_table_element_type_compatible(*exported_ty, *imported_ty)
171 && *imported_minimum <= imported_runtime_size.unwrap_or(*exported_minimum)
172 && (imported_maximum.is_none()
173 || (!exported_maximum.is_none()
174 && imported_maximum.unwrap() >= exported_maximum.unwrap()))
175}
176
177fn is_memory_compatible(
178 exported: &MemoryType,
179 imported: &MemoryType,
180 imported_runtime_size: Option<u32>,
181) -> bool {
182 let MemoryType {
183 minimum: exported_minimum,
184 maximum: exported_maximum,
185 shared: exported_shared,
186 } = exported;
187 let MemoryType {
188 minimum: imported_minimum,
189 maximum: imported_maximum,
190 shared: imported_shared,
191 } = imported;
192
193 imported_minimum.0 <= imported_runtime_size.unwrap_or(exported_minimum.0)
194 && (imported_maximum.is_none()
195 || (!exported_maximum.is_none()
196 && imported_maximum.unwrap() >= exported_maximum.unwrap()))
197 && exported_shared == imported_shared
198}
199
200macro_rules! accessors {
201 ($(($variant:ident($ty:ty) $get:ident $unwrap:ident))*) => ($(
202 pub fn $get(&self) -> Option<&$ty> {
205 if let Self::$variant(e) = self {
206 Some(e)
207 } else {
208 None
209 }
210 }
211
212 pub fn $unwrap(&self) -> &$ty {
219 self.$get().expect(concat!("expected ", stringify!($ty)))
220 }
221 )*)
222}
223
224impl ExternType {
225 accessors! {
226 (Function(FunctionType) func unwrap_func)
227 (Global(GlobalType) global unwrap_global)
228 (Table(TableType) table unwrap_table)
229 (Memory(MemoryType) memory unwrap_memory)
230 }
231 pub fn is_compatible_with(&self, other: &Self, runtime_size: Option<u32>) -> bool {
233 match (self, other) {
234 (Self::Function(a), Self::Function(b)) => a == b,
235 (Self::Global(a), Self::Global(b)) => is_global_compatible(*a, *b),
236 (Self::Table(a), Self::Table(b)) => is_table_compatible(a, b, runtime_size),
237 (Self::Memory(a), Self::Memory(b)) => is_memory_compatible(a, b, runtime_size),
238 _ => false,
240 }
241 }
242}
243
244#[derive(Debug, Clone, PartialEq, Eq, Hash)]
251#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
252#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
253#[derive(RkyvSerialize, RkyvDeserialize, Archive)]
254#[archive_attr(derive(CheckBytes, Debug))]
255pub struct FunctionType {
256 params: Box<[Type]>,
258 results: Box<[Type]>,
260}
261
262impl FunctionType {
263 pub fn new<Params, Returns>(params: Params, returns: Returns) -> Self
265 where
266 Params: Into<Box<[Type]>>,
267 Returns: Into<Box<[Type]>>,
268 {
269 Self {
270 params: params.into(),
271 results: returns.into(),
272 }
273 }
274
275 pub fn params(&self) -> &[Type] {
277 &self.params
278 }
279
280 pub fn results(&self) -> &[Type] {
282 &self.results
283 }
284}
285
286impl fmt::Display for FunctionType {
287 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
288 let params = self
289 .params
290 .iter()
291 .map(|p| format!("{:?}", p))
292 .collect::<Vec<_>>()
293 .join(", ");
294 let results = self
295 .results
296 .iter()
297 .map(|p| format!("{:?}", p))
298 .collect::<Vec<_>>()
299 .join(", ");
300 write!(f, "[{}] -> [{}]", params, results)
301 }
302}
303
304macro_rules! implement_from_pair_to_functiontype {
307 ($($N:literal,$M:literal)+) => {
308 $(
309 impl From<([Type; $N], [Type; $M])> for FunctionType {
310 fn from(pair: ([Type; $N], [Type; $M])) -> Self {
311 Self::new(pair.0, pair.1)
312 }
313 }
314 )+
315 }
316}
317
318implement_from_pair_to_functiontype! {
319 0,0 0,1 0,2 0,3 0,4 0,5 0,6 0,7 0,8 0,9
320 1,0 1,1 1,2 1,3 1,4 1,5 1,6 1,7 1,8 1,9
321 2,0 2,1 2,2 2,3 2,4 2,5 2,6 2,7 2,8 2,9
322 3,0 3,1 3,2 3,3 3,4 3,5 3,6 3,7 3,8 3,9
323 4,0 4,1 4,2 4,3 4,4 4,5 4,6 4,7 4,8 4,9
324 5,0 5,1 5,2 5,3 5,4 5,5 5,6 5,7 5,8 5,9
325 6,0 6,1 6,2 6,3 6,4 6,5 6,6 6,7 6,8 6,9
326 7,0 7,1 7,2 7,3 7,4 7,5 7,6 7,7 7,8 7,9
327 8,0 8,1 8,2 8,3 8,4 8,5 8,6 8,7 8,8 8,9
328 9,0 9,1 9,2 9,3 9,4 9,5 9,6 9,7 9,8 9,9
329}
330
331impl From<&Self> for FunctionType {
332 fn from(as_ref: &Self) -> Self {
333 as_ref.clone()
334 }
335}
336
337#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, CheckBytes)]
339#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
340#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
341#[derive(RkyvSerialize, RkyvDeserialize, Archive)]
342#[archive(as = "Self")]
343#[repr(u8)]
344pub enum Mutability {
345 Const,
347 Var,
349}
350
351impl Mutability {
352 pub fn is_mutable(self) -> bool {
354 self.into()
355 }
356}
357
358impl From<bool> for Mutability {
359 fn from(value: bool) -> Self {
360 if value {
361 Self::Var
362 } else {
363 Self::Const
364 }
365 }
366}
367
368impl From<Mutability> for bool {
369 fn from(value: Mutability) -> Self {
370 match value {
371 Mutability::Var => true,
372 Mutability::Const => false,
373 }
374 }
375}
376
377#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, CheckBytes)]
379#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
380#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
381#[derive(RkyvSerialize, RkyvDeserialize, Archive)]
382#[archive(as = "Self")]
383pub struct GlobalType {
384 pub ty: Type,
386 pub mutability: Mutability,
388}
389
390impl GlobalType {
398 pub fn new(ty: Type, mutability: Mutability) -> Self {
409 Self { ty, mutability }
410 }
411}
412
413impl fmt::Display for GlobalType {
414 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
415 let mutability = match self.mutability {
416 Mutability::Const => "constant",
417 Mutability::Var => "mutable",
418 };
419 write!(f, "{} ({})", self.ty, mutability)
420 }
421}
422
423#[derive(Debug, Clone, Copy, PartialEq)]
425#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
426#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
427#[derive(RkyvSerialize, RkyvDeserialize, Archive, rkyv::CheckBytes)]
428#[archive(as = "Self")]
429#[repr(u8)]
430pub enum GlobalInit {
431 I32Const(i32),
433 I64Const(i64),
435 F32Const(f32),
437 F64Const(f64),
439 V128Const(V128),
441 GetGlobal(GlobalIndex),
443 RefNullConst,
448 RefFunc(FunctionIndex),
450}
451
452#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
460#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
461#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
462#[derive(RkyvSerialize, RkyvDeserialize, Archive)]
463#[archive_attr(derive(CheckBytes, Debug))]
464pub struct TableType {
465 pub ty: Type,
467 pub minimum: u32,
469 pub maximum: Option<u32>,
471}
472
473impl TableType {
474 pub fn new(ty: Type, minimum: u32, maximum: Option<u32>) -> Self {
477 Self {
478 ty,
479 minimum,
480 maximum,
481 }
482 }
483}
484
485impl fmt::Display for TableType {
486 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
487 if let Some(maximum) = self.maximum {
488 write!(f, "{} ({}..{})", self.ty, self.minimum, maximum)
489 } else {
490 write!(f, "{} ({}..)", self.ty, self.minimum)
491 }
492 }
493}
494
495#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
502#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
503#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
504#[derive(RkyvSerialize, RkyvDeserialize, Archive)]
505#[archive_attr(derive(CheckBytes, Debug))]
506pub struct MemoryType {
507 pub minimum: Pages,
509 pub maximum: Option<Pages>,
511 pub shared: bool,
513}
514
515impl MemoryType {
516 pub fn new<IntoPages>(minimum: IntoPages, maximum: Option<IntoPages>, shared: bool) -> Self
519 where
520 IntoPages: Into<Pages>,
521 {
522 Self {
523 minimum: minimum.into(),
524 maximum: maximum.map(Into::into),
525 shared,
526 }
527 }
528}
529
530impl fmt::Display for MemoryType {
531 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
532 let shared = if self.shared { "shared" } else { "not shared" };
533 if let Some(maximum) = self.maximum {
534 write!(f, "{} ({:?}..{:?})", shared, self.minimum, maximum)
535 } else {
536 write!(f, "{} ({:?}..)", shared, self.minimum)
537 }
538 }
539}
540
541#[derive(Debug, Clone, PartialEq, Eq, Hash)]
550#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
551pub struct ImportType<T = ExternType> {
552 module: String,
553 name: String,
554 ty: T,
555}
556
557impl<T> ImportType<T> {
558 pub fn new(module: &str, name: &str, ty: T) -> Self {
561 Self {
562 module: module.to_owned(),
563 name: name.to_owned(),
564 ty,
565 }
566 }
567
568 pub fn module(&self) -> &str {
570 &self.module
571 }
572
573 pub fn name(&self) -> &str {
576 &self.name
577 }
578
579 pub fn ty(&self) -> &T {
581 &self.ty
582 }
583}
584
585#[derive(Debug, Clone, PartialEq, Eq, Hash)]
597#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
598pub struct ExportType<T = ExternType> {
599 name: String,
600 ty: T,
601}
602
603impl<T> ExportType<T> {
604 pub fn new(name: &str, ty: T) -> Self {
607 Self {
608 name: name.to_string(),
609 ty,
610 }
611 }
612
613 pub fn name(&self) -> &str {
615 &self.name
616 }
617
618 pub fn ty(&self) -> &T {
620 &self.ty
621 }
622}
623
624#[cfg(test)]
625mod tests {
626 use super::*;
627
628 const VOID_TO_VOID: ([Type; 0], [Type; 0]) = ([], []);
629 const I32_I32_TO_VOID: ([Type; 2], [Type; 0]) = ([Type::I32, Type::I32], []);
630 const V128_I64_TO_I32: ([Type; 2], [Type; 1]) = ([Type::V128, Type::I64], [Type::I32]);
631 const NINE_V128_TO_NINE_I32: ([Type; 9], [Type; 9]) = ([Type::V128; 9], [Type::I32; 9]);
632
633 #[test]
634 fn convert_tuple_to_functiontype() {
635 let ty: FunctionType = VOID_TO_VOID.into();
636 assert_eq!(ty.params().len(), 0);
637 assert_eq!(ty.results().len(), 0);
638
639 let ty: FunctionType = I32_I32_TO_VOID.into();
640 assert_eq!(ty.params().len(), 2);
641 assert_eq!(ty.params()[0], Type::I32);
642 assert_eq!(ty.params()[1], Type::I32);
643 assert_eq!(ty.results().len(), 0);
644
645 let ty: FunctionType = V128_I64_TO_I32.into();
646 assert_eq!(ty.params().len(), 2);
647 assert_eq!(ty.params()[0], Type::V128);
648 assert_eq!(ty.params()[1], Type::I64);
649 assert_eq!(ty.results().len(), 1);
650 assert_eq!(ty.results()[0], Type::I32);
651
652 let ty: FunctionType = NINE_V128_TO_NINE_I32.into();
653 assert_eq!(ty.params().len(), 9);
654 assert_eq!(ty.results().len(), 9);
655 }
656}