1use crate::{Encode, Section, SectionId, encode_section};
2use alloc::boxed::Box;
3use alloc::vec::Vec;
4
5#[derive(Debug, Clone)]
7pub struct SubType {
8 pub is_final: bool,
10 pub supertype_idx: Option<u32>,
13 pub composite_type: CompositeType,
15}
16
17#[derive(Debug, Clone)]
19pub struct CompositeType {
20 pub inner: CompositeInnerType,
22 pub shared: bool,
25}
26
27#[derive(Debug, Clone)]
29pub enum CompositeInnerType {
30 Func(FuncType),
32 Array(ArrayType),
34 Struct(StructType),
36 Cont(ContType),
38}
39
40#[derive(Debug, Clone, Eq, PartialEq, Hash)]
42pub struct FuncType {
43 params_results: Box<[ValType]>,
45 len_params: usize,
47}
48
49#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
51pub struct ArrayType(pub FieldType);
52
53#[derive(Debug, Clone, Eq, PartialEq, Hash)]
55pub struct StructType {
56 pub fields: Box<[FieldType]>,
58}
59
60#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
62pub struct FieldType {
63 pub element_type: StorageType,
65 pub mutable: bool,
67}
68
69#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
71pub enum StorageType {
72 I8,
74 I16,
76 Val(ValType),
78}
79
80impl StorageType {
81 pub fn is_defaultable(&self) -> bool {
83 self.unpack().is_defaultable()
84 }
85
86 pub fn unpack(&self) -> ValType {
88 match self {
89 StorageType::I8 | StorageType::I16 => ValType::I32,
90 StorageType::Val(v) => *v,
91 }
92 }
93}
94
95#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
97pub struct ContType(pub u32);
98
99#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
101pub enum ValType {
102 I32,
104 I64,
106 F32,
108 F64,
110 V128,
114 Ref(RefType),
120}
121
122impl ValType {
123 pub fn is_numeric(&self) -> bool {
125 match self {
126 ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 => true,
127 ValType::V128 | ValType::Ref(_) => false,
128 }
129 }
130
131 pub fn is_vector(&self) -> bool {
133 match self {
134 ValType::V128 => true,
135 ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::Ref(_) => false,
136 }
137 }
138
139 pub fn is_reference(&self) -> bool {
141 match self {
142 ValType::Ref(_) => true,
143 ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128 => false,
144 }
145 }
146}
147
148impl FuncType {
149 pub fn new<P, R>(params: P, results: R) -> Self
151 where
152 P: IntoIterator<Item = ValType>,
153 R: IntoIterator<Item = ValType>,
154 {
155 let mut buffer = params.into_iter().collect::<Vec<_>>();
156 let len_params = buffer.len();
157 buffer.extend(results);
158 Self::from_parts(buffer.into(), len_params)
159 }
160
161 #[inline]
162 pub(crate) fn from_parts(params_results: Box<[ValType]>, len_params: usize) -> Self {
163 Self {
164 params_results,
165 len_params,
166 }
167 }
168
169 #[inline]
171 pub fn params(&self) -> &[ValType] {
172 &self.params_results[..self.len_params]
173 }
174
175 #[inline]
177 pub fn results(&self) -> &[ValType] {
178 &self.params_results[self.len_params..]
179 }
180}
181
182impl ValType {
183 pub const FUNCREF: ValType = ValType::Ref(RefType::FUNCREF);
185 pub const EXTERNREF: ValType = ValType::Ref(RefType::EXTERNREF);
187 pub const EXNREF: ValType = ValType::Ref(RefType::EXNREF);
189
190 pub fn is_defaultable(&self) -> bool {
192 match self {
193 ValType::Ref(r) => r.nullable,
194 ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128 => true,
195 }
196 }
197}
198
199impl Encode for StorageType {
200 fn encode(&self, sink: &mut Vec<u8>) {
201 match self {
202 StorageType::I8 => sink.push(0x78),
203 StorageType::I16 => sink.push(0x77),
204 StorageType::Val(vt) => vt.encode(sink),
205 }
206 }
207}
208
209impl Encode for ValType {
210 fn encode(&self, sink: &mut Vec<u8>) {
211 match self {
212 ValType::I32 => sink.push(0x7F),
213 ValType::I64 => sink.push(0x7E),
214 ValType::F32 => sink.push(0x7D),
215 ValType::F64 => sink.push(0x7C),
216 ValType::V128 => sink.push(0x7B),
217 ValType::Ref(rt) => rt.encode(sink),
218 }
219 }
220}
221
222#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
228#[allow(missing_docs)]
229pub struct RefType {
230 pub nullable: bool,
231 pub heap_type: HeapType,
232}
233
234impl RefType {
235 pub const ANYREF: RefType = RefType {
237 nullable: true,
238 heap_type: HeapType::Abstract {
239 shared: false,
240 ty: AbstractHeapType::Any,
241 },
242 };
243
244 pub const EQREF: RefType = RefType {
246 nullable: true,
247 heap_type: HeapType::Abstract {
248 shared: false,
249 ty: AbstractHeapType::Eq,
250 },
251 };
252
253 pub const FUNCREF: RefType = RefType {
255 nullable: true,
256 heap_type: HeapType::Abstract {
257 shared: false,
258 ty: AbstractHeapType::Func,
259 },
260 };
261
262 pub const EXTERNREF: RefType = RefType {
264 nullable: true,
265 heap_type: HeapType::Abstract {
266 shared: false,
267 ty: AbstractHeapType::Extern,
268 },
269 };
270
271 pub const I31REF: RefType = RefType {
273 nullable: true,
274 heap_type: HeapType::Abstract {
275 shared: false,
276 ty: AbstractHeapType::I31,
277 },
278 };
279
280 pub const ARRAYREF: RefType = RefType {
282 nullable: true,
283 heap_type: HeapType::Abstract {
284 shared: false,
285 ty: AbstractHeapType::Array,
286 },
287 };
288
289 pub const EXNREF: RefType = RefType {
291 nullable: true,
292 heap_type: HeapType::Abstract {
293 shared: false,
294 ty: AbstractHeapType::Exn,
295 },
296 };
297
298 pub fn new_abstract(ty: AbstractHeapType, nullable: bool, shared: bool) -> Self {
300 Self {
301 nullable,
302 heap_type: HeapType::Abstract { shared, ty },
303 }
304 }
305
306 pub fn nullable(mut self, nullable: bool) -> Self {
308 self.nullable = nullable;
309 self
310 }
311}
312
313impl Encode for RefType {
314 fn encode(&self, sink: &mut Vec<u8>) {
315 match self {
316 RefType {
319 nullable: true,
320 heap_type: heap @ HeapType::Abstract { .. },
321 } => {
322 heap.encode(sink);
323 }
324
325 RefType {
327 nullable: true,
328 heap_type,
329 } => {
330 sink.push(0x63);
331 heap_type.encode(sink);
332 }
333
334 RefType {
336 nullable: false,
337 heap_type,
338 } => {
339 sink.push(0x64);
340 heap_type.encode(sink);
341 }
342 }
343 }
344}
345
346impl From<RefType> for ValType {
347 fn from(ty: RefType) -> ValType {
348 ValType::Ref(ty)
349 }
350}
351
352#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
354pub enum HeapType {
355 Abstract {
357 shared: bool,
359 ty: AbstractHeapType,
361 },
362
363 Concrete(u32),
365}
366
367impl HeapType {
368 pub const ANY: Self = Self::Abstract {
370 shared: false,
371 ty: AbstractHeapType::Any,
372 };
373
374 pub const FUNC: Self = Self::Abstract {
376 shared: false,
377 ty: AbstractHeapType::Func,
378 };
379
380 pub const EXTERN: Self = Self::Abstract {
382 shared: false,
383 ty: AbstractHeapType::Extern,
384 };
385
386 pub const I31: Self = Self::Abstract {
388 shared: false,
389 ty: AbstractHeapType::I31,
390 };
391}
392
393impl Encode for HeapType {
394 fn encode(&self, sink: &mut Vec<u8>) {
395 match self {
396 HeapType::Abstract { shared, ty } => {
397 if *shared {
398 sink.push(0x65);
399 }
400 ty.encode(sink);
401 }
402 HeapType::Concrete(i) => i64::from(*i).encode(sink),
405 }
406 }
407}
408
409#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
411pub enum AbstractHeapType {
412 Func,
414
415 Extern,
417
418 Any,
422
423 None,
427
428 NoExtern,
432
433 NoFunc,
437
438 Eq,
443
444 Struct,
448
449 Array,
453
454 I31,
456
457 Exn,
459
460 NoExn,
462
463 Cont,
465
466 NoCont,
468}
469
470impl Encode for AbstractHeapType {
471 fn encode(&self, sink: &mut Vec<u8>) {
472 use AbstractHeapType::*;
473 match self {
474 Func => sink.push(0x70),
475 Extern => sink.push(0x6F),
476 Any => sink.push(0x6E),
477 None => sink.push(0x71),
478 NoExtern => sink.push(0x72),
479 NoFunc => sink.push(0x73),
480 Eq => sink.push(0x6D),
481 Struct => sink.push(0x6B),
482 Array => sink.push(0x6A),
483 I31 => sink.push(0x6C),
484 Exn => sink.push(0x69),
485 NoExn => sink.push(0x74),
486 Cont => sink.push(0x68),
487 NoCont => sink.push(0x75),
488 }
489 }
490}
491
492#[derive(Clone, Debug, Default)]
509pub struct TypeSection {
510 bytes: Vec<u8>,
511 num_added: u32,
512}
513
514impl TypeSection {
515 pub fn new() -> Self {
517 Self::default()
518 }
519
520 pub fn len(&self) -> u32 {
522 self.num_added
523 }
524
525 pub fn is_empty(&self) -> bool {
527 self.num_added == 0
528 }
529
530 #[must_use = "the encoder must be used to encode the type"]
532 pub fn ty(&mut self) -> CoreTypeEncoder<'_> {
533 self.num_added += 1;
534 CoreTypeEncoder {
535 bytes: &mut self.bytes,
536 push_prefix_if_component_core_type: false,
537 }
538 }
539}
540
541impl Encode for TypeSection {
542 fn encode(&self, sink: &mut Vec<u8>) {
543 encode_section(sink, self.num_added, &self.bytes);
544 }
545}
546
547impl Section for TypeSection {
548 fn id(&self) -> u8 {
549 SectionId::Type.into()
550 }
551}
552
553#[derive(Debug)]
556pub struct CoreTypeEncoder<'a> {
557 pub(crate) bytes: &'a mut Vec<u8>,
558 pub(crate) push_prefix_if_component_core_type: bool,
566}
567impl<'a> CoreTypeEncoder<'a> {
568 pub fn function<P, R>(mut self, params: P, results: R)
570 where
571 P: IntoIterator<Item = ValType>,
572 P::IntoIter: ExactSizeIterator,
573 R: IntoIterator<Item = ValType>,
574 R::IntoIter: ExactSizeIterator,
575 {
576 self.encode_function(params, results);
577 }
578
579 pub fn func_type(mut self, ty: &FuncType) {
581 self.encode_function(ty.params().iter().cloned(), ty.results().iter().cloned());
582 }
583
584 fn encode_function<P, R>(&mut self, params: P, results: R)
585 where
586 P: IntoIterator<Item = ValType>,
587 P::IntoIter: ExactSizeIterator,
588 R: IntoIterator<Item = ValType>,
589 R::IntoIter: ExactSizeIterator,
590 {
591 let params = params.into_iter();
592 let results = results.into_iter();
593
594 self.bytes.push(0x60);
595 params.len().encode(self.bytes);
596 params.for_each(|p| p.encode(self.bytes));
597 results.len().encode(self.bytes);
598 results.for_each(|p| p.encode(self.bytes));
599 }
600
601 pub fn array(mut self, ty: &StorageType, mutable: bool) {
603 self.encode_array(ty, mutable);
604 }
605
606 fn encode_array(&mut self, ty: &StorageType, mutable: bool) {
607 self.bytes.push(0x5e);
608 self.encode_field(ty, mutable);
609 }
610
611 fn encode_field(&mut self, ty: &StorageType, mutable: bool) {
612 ty.encode(self.bytes);
613 self.bytes.push(mutable as u8);
614 }
615
616 pub fn struct_<F>(mut self, fields: F)
618 where
619 F: IntoIterator<Item = FieldType>,
620 F::IntoIter: ExactSizeIterator,
621 {
622 self.encode_struct(fields);
623 }
624
625 fn encode_struct<F>(&mut self, fields: F)
626 where
627 F: IntoIterator<Item = FieldType>,
628 F::IntoIter: ExactSizeIterator,
629 {
630 let fields = fields.into_iter();
631 self.bytes.push(0x5f);
632 fields.len().encode(self.bytes);
633 for f in fields {
634 self.encode_field(&f.element_type, f.mutable);
635 }
636 }
637
638 pub fn cont(mut self, ty: &ContType) {
640 self.encode_cont(ty)
641 }
642
643 fn encode_cont(&mut self, ty: &ContType) {
644 self.bytes.push(0x5d);
645 i64::from(ty.0).encode(self.bytes);
646 }
647
648 pub fn subtype(mut self, ty: &SubType) {
650 self.encode_subtype(ty)
651 }
652
653 fn encode_subtype(&mut self, ty: &SubType) {
655 if ty.supertype_idx.is_some() || !ty.is_final {
659 if ty.is_final {
660 self.bytes.push(0x4f);
661 } else {
662 if self.push_prefix_if_component_core_type {
663 self.bytes.push(0x00);
664 }
665 self.bytes.push(0x50);
666 }
667 ty.supertype_idx.encode(self.bytes);
668 }
669 if ty.composite_type.shared {
670 self.bytes.push(0x65);
671 }
672 match &ty.composite_type.inner {
673 CompositeInnerType::Func(ty) => {
674 self.encode_function(ty.params().iter().copied(), ty.results().iter().copied())
675 }
676 CompositeInnerType::Array(ArrayType(ty)) => {
677 self.encode_array(&ty.element_type, ty.mutable)
678 }
679 CompositeInnerType::Struct(ty) => self.encode_struct(ty.fields.iter().cloned()),
680 CompositeInnerType::Cont(ty) => self.encode_cont(ty),
681 }
682 }
683
684 pub fn rec<T>(mut self, types: T)
686 where
687 T: IntoIterator<Item = SubType>,
688 T::IntoIter: ExactSizeIterator,
689 {
690 self.push_prefix_if_component_core_type = false;
694 let types = types.into_iter();
695 self.bytes.push(0x4e);
696 types.len().encode(self.bytes);
697 types.for_each(|t| {
698 self.encode_subtype(&t);
699 });
700 }
701}
702
703#[cfg(test)]
704mod tests {
705 use super::*;
706 use crate::Module;
707 use wasmparser::WasmFeatures;
708
709 #[test]
710 fn func_types_dont_require_wasm_gc() {
711 let mut types = TypeSection::new();
712 types.ty().subtype(&SubType {
713 is_final: true,
714 supertype_idx: None,
715 composite_type: CompositeType {
716 inner: CompositeInnerType::Func(FuncType::new([], [])),
717 shared: false,
718 },
719 });
720
721 let mut module = Module::new();
722 module.section(&types);
723 let wasm_bytes = module.finish();
724
725 let mut validator =
726 wasmparser::Validator::new_with_features(WasmFeatures::default() & !WasmFeatures::GC);
727
728 validator.validate_all(&wasm_bytes).expect(
729 "Encoding pre Wasm GC type should not accidentally use Wasm GC specific encoding",
730 );
731 }
732}