1 | use crate::{BinaryReader, ComponentTypeRef, FromReader, Result, SectionLimited}; |
2 | |
3 | /// Represents the kind of an external items of a WebAssembly component. |
4 | #[derive (Clone, Copy, Debug, Eq, PartialEq)] |
5 | pub enum ComponentExternalKind { |
6 | /// The external kind is a core module. |
7 | Module, |
8 | /// The external kind is a function. |
9 | Func, |
10 | /// The external kind is a value. |
11 | Value, |
12 | /// The external kind is a type. |
13 | Type, |
14 | /// The external kind is an instance. |
15 | Instance, |
16 | /// The external kind is a component. |
17 | Component, |
18 | } |
19 | |
20 | impl ComponentExternalKind { |
21 | pub(crate) fn from_bytes( |
22 | byte1: u8, |
23 | byte2: Option<u8>, |
24 | offset: usize, |
25 | ) -> Result<ComponentExternalKind> { |
26 | Ok(match byte1 { |
27 | 0x00 => match byte2.unwrap() { |
28 | 0x11 => ComponentExternalKind::Module, |
29 | x => { |
30 | return Err(BinaryReader::invalid_leading_byte_error( |
31 | x, |
32 | "component external kind" , |
33 | offset + 1, |
34 | )) |
35 | } |
36 | }, |
37 | 0x01 => ComponentExternalKind::Func, |
38 | 0x02 => ComponentExternalKind::Value, |
39 | 0x03 => ComponentExternalKind::Type, |
40 | 0x04 => ComponentExternalKind::Component, |
41 | 0x05 => ComponentExternalKind::Instance, |
42 | x => { |
43 | return Err(BinaryReader::invalid_leading_byte_error( |
44 | x, |
45 | "component external kind" , |
46 | offset, |
47 | )) |
48 | } |
49 | }) |
50 | } |
51 | |
52 | /// Returns a simple string description of this kind. |
53 | pub fn desc(&self) -> &'static str { |
54 | use ComponentExternalKind::*; |
55 | match self { |
56 | Module => "module" , |
57 | Func => "func" , |
58 | Value => "value" , |
59 | Type => "type" , |
60 | Instance => "instance" , |
61 | Component => "component" , |
62 | } |
63 | } |
64 | } |
65 | |
66 | /// Represents an export in a WebAssembly component. |
67 | #[derive (Debug, Clone, Eq, PartialEq)] |
68 | pub struct ComponentExport<'a> { |
69 | /// The name of the exported item. |
70 | pub name: ComponentExportName<'a>, |
71 | /// The kind of the export. |
72 | pub kind: ComponentExternalKind, |
73 | /// The index of the exported item. |
74 | pub index: u32, |
75 | /// An optionally specified type ascribed to this export. |
76 | pub ty: Option<ComponentTypeRef>, |
77 | } |
78 | |
79 | /// A reader for the export section of a WebAssembly component. |
80 | pub type ComponentExportSectionReader<'a> = SectionLimited<'a, ComponentExport<'a>>; |
81 | |
82 | impl<'a> FromReader<'a> for ComponentExport<'a> { |
83 | fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { |
84 | Ok(ComponentExport { |
85 | name: reader.read()?, |
86 | kind: reader.read()?, |
87 | index: reader.read()?, |
88 | ty: match reader.read_u8()? { |
89 | 0x00 => None, |
90 | 0x01 => Some(reader.read()?), |
91 | other: u8 => { |
92 | return Err(BinaryReader::invalid_leading_byte_error( |
93 | byte:other, |
94 | desc:"optional component export type" , |
95 | offset:reader.original_position() - 1, |
96 | )) |
97 | } |
98 | }, |
99 | }) |
100 | } |
101 | } |
102 | |
103 | impl<'a> FromReader<'a> for ComponentExternalKind { |
104 | fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { |
105 | let offset: usize = reader.original_position(); |
106 | let byte1: u8 = reader.read_u8()?; |
107 | let byte2: Option = if byte1 == 0x00 { |
108 | Some(reader.read_u8()?) |
109 | } else { |
110 | None |
111 | }; |
112 | |
113 | ComponentExternalKind::from_bytes(byte1, byte2, offset) |
114 | } |
115 | } |
116 | |
117 | /// Represents the name of a component export. |
118 | #[derive (Debug, Copy, Clone, Eq, PartialEq)] |
119 | #[allow (missing_docs)] |
120 | pub struct ComponentExportName<'a>(pub &'a str); |
121 | |
122 | impl<'a> FromReader<'a> for ComponentExportName<'a> { |
123 | fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { |
124 | match reader.read_u8()? { |
125 | 0x00 => {} |
126 | // Historically export names used a discriminator byte of 0x01 to |
127 | // indicate an "interface" of the form `a:b/c` but nowadays that's |
128 | // inferred from string syntax. Ignore 0-vs-1 to continue to parse |
129 | // older binaries. Eventually this will go away. |
130 | 0x01 => {} |
131 | x: u8 => return reader.invalid_leading_byte(byte:x, desc:"export name" ), |
132 | } |
133 | Ok(ComponentExportName(reader.read_string()?)) |
134 | } |
135 | } |
136 | |