1use crate::limits::*;
2use crate::prelude::*;
3use crate::RecGroup;
4use crate::{
5 BinaryReader, ComponentAlias, ComponentExportName, ComponentImport, ComponentTypeRef,
6 FromReader, Import, Result, SectionLimited, TypeRef, ValType,
7};
8use core::fmt;
9
10/// Represents the kind of an outer core alias in a WebAssembly component.
11#[derive(Clone, Copy, Debug, Eq, PartialEq)]
12pub enum OuterAliasKind {
13 /// The alias is to a core type.
14 Type,
15}
16
17/// Represents a core type in a WebAssembly component.
18#[derive(Debug, Clone, Eq, PartialEq)]
19pub enum CoreType<'a> {
20 /// The type is for a core subtype.
21 Rec(RecGroup),
22 /// The type is for a core module.
23 Module(Box<[ModuleTypeDeclaration<'a>]>),
24}
25
26impl<'a> FromReader<'a> for CoreType<'a> {
27 fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
28 // For the time being, this special logic handles an ambiguous encoding
29 // in the component model: the `0x50` opcode represents both a core
30 // module type as well as a GC non-final `sub` type. To avoid this, the
31 // component model specification requires us to prefix a non-final `sub`
32 // type with `0x00` when it is used as a top-level core type of a
33 // component. Eventually (prior to the component model's v1.0 release),
34 // a module type will get a new opcode and this special logic can go
35 // away.
36 Ok(match reader.peek()? {
37 0x00 => {
38 reader.read_u8()?;
39 let x = reader.peek()?;
40 if x != 0x50 {
41 return reader.invalid_leading_byte(x, "non-final sub type");
42 }
43 CoreType::Rec(reader.read()?)
44 }
45 0x50 => {
46 reader.read_u8()?;
47 CoreType::Module(
48 reader
49 .read_iter(MAX_WASM_MODULE_TYPE_DECLS, "module type declaration")?
50 .collect::<Result<_>>()?,
51 )
52 }
53 _ => CoreType::Rec(reader.read()?),
54 })
55 }
56}
57
58/// Represents a module type declaration in a WebAssembly component.
59#[derive(Debug, Clone, Eq, PartialEq)]
60pub enum ModuleTypeDeclaration<'a> {
61 /// The module type definition is for a type.
62 Type(RecGroup),
63 /// The module type definition is for an export.
64 Export {
65 /// The name of the exported item.
66 name: &'a str,
67 /// The type reference of the export.
68 ty: TypeRef,
69 },
70 /// The module type declaration is for an outer alias.
71 OuterAlias {
72 /// The alias kind.
73 kind: OuterAliasKind,
74 /// The outward count, starting at zero for the current type.
75 count: u32,
76 /// The index of the item within the outer type.
77 index: u32,
78 },
79 /// The module type definition is for an import.
80 Import(Import<'a>),
81}
82
83impl<'a> FromReader<'a> for ModuleTypeDeclaration<'a> {
84 fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
85 Ok(match reader.read_u8()? {
86 0x00 => ModuleTypeDeclaration::Import(reader.read()?),
87 0x01 => ModuleTypeDeclaration::Type(reader.read()?),
88 0x02 => {
89 let kind = match reader.read_u8()? {
90 0x10 => OuterAliasKind::Type,
91 x => {
92 return reader.invalid_leading_byte(x, "outer alias kind");
93 }
94 };
95 match reader.read_u8()? {
96 0x01 => ModuleTypeDeclaration::OuterAlias {
97 kind,
98 count: reader.read()?,
99 index: reader.read()?,
100 },
101 x => {
102 return reader.invalid_leading_byte(x, "outer alias target");
103 }
104 }
105 }
106 0x03 => ModuleTypeDeclaration::Export {
107 name: reader.read()?,
108 ty: reader.read()?,
109 },
110 x => return reader.invalid_leading_byte(x, "type definition"),
111 })
112 }
113}
114
115/// A reader for the core type section of a WebAssembly component.
116///
117/// # Examples
118/// ```
119/// use wasmparser::{CoreTypeSectionReader, BinaryReader};
120/// # let data: &[u8] = &[0x01, 0x60, 0x00, 0x00];
121/// let reader = BinaryReader::new(data, 0);
122/// let mut reader = CoreTypeSectionReader::new(reader).unwrap();
123/// for ty in reader {
124/// println!("Type {:?}", ty.expect("type"));
125/// }
126/// ```
127pub type CoreTypeSectionReader<'a> = SectionLimited<'a, CoreType<'a>>;
128
129/// Represents a value type in a WebAssembly component.
130#[derive(Debug, Clone, Copy, PartialEq, Eq)]
131pub enum ComponentValType {
132 /// The value type is a primitive type.
133 Primitive(PrimitiveValType),
134 /// The value type is a reference to a defined type.
135 Type(u32),
136}
137
138impl<'a> FromReader<'a> for ComponentValType {
139 fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
140 if let Some(ty: PrimitiveValType) = PrimitiveValType::from_byte(reader.peek()?) {
141 reader.read_u8()?;
142 return Ok(ComponentValType::Primitive(ty));
143 }
144
145 Ok(ComponentValType::Type(reader.read_var_s33()? as u32))
146 }
147}
148
149impl<'a> FromReader<'a> for Option<ComponentValType> {
150 fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
151 match reader.read_u8()? {
152 0x0 => Ok(None),
153 0x1 => Ok(Some(reader.read()?)),
154 x: u8 => reader.invalid_leading_byte(byte:x, desc:"optional component value type"),
155 }
156 }
157}
158
159/// Represents a primitive value type.
160#[derive(Debug, Clone, Copy, PartialEq, Eq)]
161pub enum PrimitiveValType {
162 /// The type is a boolean.
163 Bool,
164 /// The type is a signed 8-bit integer.
165 S8,
166 /// The type is an unsigned 8-bit integer.
167 U8,
168 /// The type is a signed 16-bit integer.
169 S16,
170 /// The type is an unsigned 16-bit integer.
171 U16,
172 /// The type is a signed 32-bit integer.
173 S32,
174 /// The type is an unsigned 32-bit integer.
175 U32,
176 /// The type is a signed 64-bit integer.
177 S64,
178 /// The type is an unsigned 64-bit integer.
179 U64,
180 /// The type is a 32-bit floating point number with only one NaN.
181 F32,
182 /// The type is a 64-bit floating point number with only one NaN.
183 F64,
184 /// The type is a Unicode character.
185 Char,
186 /// The type is a string.
187 String,
188}
189
190impl PrimitiveValType {
191 fn from_byte(byte: u8) -> Option<PrimitiveValType> {
192 Some(match byte {
193 0x7f => PrimitiveValType::Bool,
194 0x7e => PrimitiveValType::S8,
195 0x7d => PrimitiveValType::U8,
196 0x7c => PrimitiveValType::S16,
197 0x7b => PrimitiveValType::U16,
198 0x7a => PrimitiveValType::S32,
199 0x79 => PrimitiveValType::U32,
200 0x78 => PrimitiveValType::S64,
201 0x77 => PrimitiveValType::U64,
202 0x76 => PrimitiveValType::F32,
203 0x75 => PrimitiveValType::F64,
204 0x74 => PrimitiveValType::Char,
205 0x73 => PrimitiveValType::String,
206 _ => return None,
207 })
208 }
209
210 #[cfg(feature = "validate")]
211 pub(crate) fn contains_ptr(&self) -> bool {
212 matches!(self, Self::String)
213 }
214
215 /// Determines if primitive value type `a` is a subtype of `b`.
216 pub fn is_subtype_of(a: Self, b: Self) -> bool {
217 // Note that this intentionally diverges from the upstream specification
218 // at this time and only considers exact equality for subtyping
219 // relationships.
220 //
221 // More information can be found in the subtyping implementation for
222 // component functions.
223 a == b
224 }
225}
226
227impl fmt::Display for PrimitiveValType {
228 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
229 use PrimitiveValType::*;
230 let s: &'static str = match self {
231 Bool => "bool",
232 S8 => "s8",
233 U8 => "u8",
234 S16 => "s16",
235 U16 => "u16",
236 S32 => "s32",
237 U32 => "u32",
238 S64 => "s64",
239 U64 => "u64",
240 F32 => "f32",
241 F64 => "f64",
242 Char => "char",
243 String => "string",
244 };
245 s.fmt(f)
246 }
247}
248
249/// Represents a type in a WebAssembly component.
250#[derive(Debug, Clone, Eq, PartialEq)]
251pub enum ComponentType<'a> {
252 /// The type is a component defined type.
253 Defined(ComponentDefinedType<'a>),
254 /// The type is a function type.
255 Func(ComponentFuncType<'a>),
256 /// The type is a component type.
257 Component(Box<[ComponentTypeDeclaration<'a>]>),
258 /// The type is an instance type.
259 Instance(Box<[InstanceTypeDeclaration<'a>]>),
260 /// The type is a fresh new resource type.
261 Resource {
262 /// The representation of this resource type in core WebAssembly.
263 rep: ValType,
264 /// An optionally-specified destructor to use for when this resource is
265 /// no longer needed.
266 dtor: Option<u32>,
267 },
268}
269
270impl<'a> FromReader<'a> for ComponentType<'a> {
271 fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
272 Ok(match reader.read_u8()? {
273 0x3f => ComponentType::Resource {
274 rep: reader.read()?,
275 dtor: match reader.read_u8()? {
276 0x00 => None,
277 0x01 => Some(reader.read()?),
278 b => return reader.invalid_leading_byte(b, "resource destructor"),
279 },
280 },
281 0x40 => {
282 let params = reader
283 .read_iter(MAX_WASM_FUNCTION_PARAMS, "component function parameters")?
284 .collect::<Result<_>>()?;
285 let results = reader.read()?;
286 ComponentType::Func(ComponentFuncType { params, results })
287 }
288 0x41 => ComponentType::Component(
289 reader
290 .read_iter(MAX_WASM_COMPONENT_TYPE_DECLS, "component type declaration")?
291 .collect::<Result<_>>()?,
292 ),
293 0x42 => ComponentType::Instance(
294 reader
295 .read_iter(MAX_WASM_INSTANCE_TYPE_DECLS, "instance type declaration")?
296 .collect::<Result<_>>()?,
297 ),
298 x => {
299 if let Some(ty) = PrimitiveValType::from_byte(x) {
300 ComponentType::Defined(ComponentDefinedType::Primitive(ty))
301 } else {
302 ComponentType::Defined(ComponentDefinedType::read(reader, x)?)
303 }
304 }
305 })
306 }
307}
308
309/// Represents part of a component type declaration in a WebAssembly component.
310#[derive(Debug, Clone, Eq, PartialEq)]
311pub enum ComponentTypeDeclaration<'a> {
312 /// The component type declaration is for a core type.
313 CoreType(CoreType<'a>),
314 /// The component type declaration is for a type.
315 Type(ComponentType<'a>),
316 /// The component type declaration is for an alias.
317 Alias(ComponentAlias<'a>),
318 /// The component type declaration is for an export.
319 Export {
320 /// The name of the export.
321 name: ComponentExportName<'a>,
322 /// The type reference for the export.
323 ty: ComponentTypeRef,
324 },
325 /// The component type declaration is for an import.
326 Import(ComponentImport<'a>),
327}
328
329impl<'a> FromReader<'a> for ComponentTypeDeclaration<'a> {
330 fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
331 // Component types are effectively instance types with the additional
332 // variant of imports; check for imports here or delegate to
333 // `InstanceTypeDeclaration` with the appropriate conversions.
334 if reader.peek()? == 0x03 {
335 reader.read_u8()?;
336 return Ok(ComponentTypeDeclaration::Import(reader.read()?));
337 }
338
339 Ok(match reader.read()? {
340 InstanceTypeDeclaration::CoreType(t: CoreType<'_>) => ComponentTypeDeclaration::CoreType(t),
341 InstanceTypeDeclaration::Type(t: ComponentType<'_>) => ComponentTypeDeclaration::Type(t),
342 InstanceTypeDeclaration::Alias(a: ComponentAlias<'_>) => ComponentTypeDeclaration::Alias(a),
343 InstanceTypeDeclaration::Export { name: ComponentExportName<'_>, ty: ComponentTypeRef } => {
344 ComponentTypeDeclaration::Export { name, ty }
345 }
346 })
347 }
348}
349
350/// Represents an instance type declaration in a WebAssembly component.
351#[derive(Debug, Clone, Eq, PartialEq)]
352pub enum InstanceTypeDeclaration<'a> {
353 /// The component type declaration is for a core type.
354 CoreType(CoreType<'a>),
355 /// The instance type declaration is for a type.
356 Type(ComponentType<'a>),
357 /// The instance type declaration is for an alias.
358 Alias(ComponentAlias<'a>),
359 /// The instance type declaration is for an export.
360 Export {
361 /// The name of the export.
362 name: ComponentExportName<'a>,
363 /// The type reference for the export.
364 ty: ComponentTypeRef,
365 },
366}
367
368impl<'a> FromReader<'a> for InstanceTypeDeclaration<'a> {
369 fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
370 Ok(match reader.read_u8()? {
371 0x00 => InstanceTypeDeclaration::CoreType(reader.read()?),
372 0x01 => InstanceTypeDeclaration::Type(reader.read()?),
373 0x02 => InstanceTypeDeclaration::Alias(reader.read()?),
374 0x04 => InstanceTypeDeclaration::Export {
375 name: reader.read()?,
376 ty: reader.read()?,
377 },
378 x: u8 => return reader.invalid_leading_byte(byte:x, desc:"component or instance type declaration"),
379 })
380 }
381}
382
383/// Represents the result type of a component function.
384#[derive(Debug, Clone, Eq, PartialEq)]
385pub enum ComponentFuncResult<'a> {
386 /// The function returns a singular, unnamed type.
387 Unnamed(ComponentValType),
388 /// The function returns zero or more named types.
389 Named(Box<[(&'a str, ComponentValType)]>),
390}
391
392impl<'a> FromReader<'a> for ComponentFuncResult<'a> {
393 fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
394 Ok(match reader.read_u8()? {
395 0x00 => ComponentFuncResult::Unnamed(reader.read()?),
396 0x01 => ComponentFuncResult::Named(
397 readerBinaryReaderIter<'a, '_, …>
398 .read_iter(MAX_WASM_FUNCTION_RETURNS, desc:"component function results")?
399 .collect::<Result<_>>()?,
400 ),
401 x: u8 => return reader.invalid_leading_byte(byte:x, desc:"component function results"),
402 })
403 }
404}
405
406impl ComponentFuncResult<'_> {
407 /// Gets the count of types returned by the function.
408 pub fn type_count(&self) -> usize {
409 match self {
410 Self::Unnamed(_) => 1,
411 Self::Named(vec) => vec.len(),
412 }
413 }
414
415 /// Iterates over the types returned by the function.
416 pub fn iter(&self) -> impl Iterator<Item = (Option<&str>, &ComponentValType)> {
417 enum Either<L, R> {
418 Left(L),
419 Right(R),
420 }
421
422 impl<L, R> Iterator for Either<L, R>
423 where
424 L: Iterator,
425 R: Iterator<Item = L::Item>,
426 {
427 type Item = L::Item;
428
429 fn next(&mut self) -> Option<Self::Item> {
430 match self {
431 Either::Left(l) => l.next(),
432 Either::Right(r) => r.next(),
433 }
434 }
435 }
436
437 match self {
438 Self::Unnamed(ty) => Either::Left(core::iter::once(ty).map(|ty| (None, ty))),
439 Self::Named(vec) => Either::Right(vec.iter().map(|(n, ty)| (Some(*n), ty))),
440 }
441 }
442}
443
444/// Represents a type of a function in a WebAssembly component.
445#[derive(Debug, Clone, Eq, PartialEq)]
446pub struct ComponentFuncType<'a> {
447 /// The function parameters.
448 pub params: Box<[(&'a str, ComponentValType)]>,
449 /// The function result.
450 pub results: ComponentFuncResult<'a>,
451}
452
453/// Represents a case in a variant type.
454#[derive(Debug, Clone, PartialEq, Eq)]
455pub struct VariantCase<'a> {
456 /// The name of the variant case.
457 pub name: &'a str,
458 /// The value type of the variant case.
459 pub ty: Option<ComponentValType>,
460 /// The index of the variant case that is refined by this one.
461 pub refines: Option<u32>,
462}
463
464impl<'a> FromReader<'a> for VariantCase<'a> {
465 fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
466 Ok(VariantCase {
467 name: reader.read()?,
468 ty: reader.read()?,
469 refines: match reader.read_u8()? {
470 0x0 => None,
471 0x1 => Some(reader.read_var_u32()?),
472 x: u8 => return reader.invalid_leading_byte(byte:x, desc:"variant case refines"),
473 },
474 })
475 }
476}
477
478/// Represents a defined type in a WebAssembly component.
479#[derive(Debug, Clone, PartialEq, Eq)]
480pub enum ComponentDefinedType<'a> {
481 /// The type is one of the primitive value types.
482 Primitive(PrimitiveValType),
483 /// The type is a record with the given fields.
484 Record(Box<[(&'a str, ComponentValType)]>),
485 /// The type is a variant with the given cases.
486 Variant(Box<[VariantCase<'a>]>),
487 /// The type is a list of the given value type.
488 List(ComponentValType),
489 /// The type is a tuple of the given value types.
490 Tuple(Box<[ComponentValType]>),
491 /// The type is flags with the given names.
492 Flags(Box<[&'a str]>),
493 /// The type is an enum with the given tags.
494 Enum(Box<[&'a str]>),
495 /// The type is an option of the given value type.
496 Option(ComponentValType),
497 /// The type is a result type.
498 Result {
499 /// The type returned for success.
500 ok: Option<ComponentValType>,
501 /// The type returned for failure.
502 err: Option<ComponentValType>,
503 },
504 /// An owned handle to a resource.
505 Own(u32),
506 /// A borrowed handle to a resource.
507 Borrow(u32),
508 /// A future type with the specified payload type.
509 Future(Option<ComponentValType>),
510 /// A stream type with the specified payload type.
511 Stream(ComponentValType),
512 /// The error-context type.
513 ErrorContext,
514}
515
516impl<'a> ComponentDefinedType<'a> {
517 fn read(reader: &mut BinaryReader<'a>, byte: u8) -> Result<ComponentDefinedType<'a>> {
518 Ok(match byte {
519 0x72 => ComponentDefinedType::Record(
520 reader
521 .read_iter(MAX_WASM_RECORD_FIELDS, "record field")?
522 .collect::<Result<_>>()?,
523 ),
524 0x71 => ComponentDefinedType::Variant(
525 reader
526 .read_iter(MAX_WASM_VARIANT_CASES, "variant cases")?
527 .collect::<Result<_>>()?,
528 ),
529 0x70 => ComponentDefinedType::List(reader.read()?),
530 0x6f => ComponentDefinedType::Tuple(
531 reader
532 .read_iter(MAX_WASM_TUPLE_TYPES, "tuple types")?
533 .collect::<Result<_>>()?,
534 ),
535 0x6e => ComponentDefinedType::Flags(
536 reader
537 .read_iter(MAX_WASM_FLAG_NAMES, "flag names")?
538 .collect::<Result<_>>()?,
539 ),
540 0x6d => ComponentDefinedType::Enum(
541 reader
542 .read_iter(MAX_WASM_ENUM_CASES, "enum cases")?
543 .collect::<Result<_>>()?,
544 ),
545 // NOTE: 0x6c (union) removed
546 0x6b => ComponentDefinedType::Option(reader.read()?),
547 0x6a => ComponentDefinedType::Result {
548 ok: reader.read()?,
549 err: reader.read()?,
550 },
551 0x69 => ComponentDefinedType::Own(reader.read()?),
552 0x68 => ComponentDefinedType::Borrow(reader.read()?),
553 0x67 => ComponentDefinedType::Future(reader.read()?),
554 0x66 => ComponentDefinedType::Stream(reader.read()?),
555 0x65 => ComponentDefinedType::ErrorContext,
556 x => return reader.invalid_leading_byte(x, "component defined type"),
557 })
558 }
559}
560
561/// A reader for the type section of a WebAssembly component.
562///
563/// # Examples
564///
565/// ```
566/// use wasmparser::{ComponentTypeSectionReader, BinaryReader};
567/// let data: &[u8] = &[0x01, 0x40, 0x01, 0x03, b'f', b'o', b'o', 0x73, 0x00, 0x73];
568/// let reader = BinaryReader::new(data, 0);
569/// let mut reader = ComponentTypeSectionReader::new(reader).unwrap();
570/// for ty in reader {
571/// println!("Type {:?}", ty.expect("type"));
572/// }
573/// ```
574pub type ComponentTypeSectionReader<'a> = SectionLimited<'a, ComponentType<'a>>;
575