1 | use crate::{ |
2 | encode_section, ComponentExportKind, ComponentSection, ComponentSectionId, ComponentValType, |
3 | Encode, |
4 | }; |
5 | |
6 | /// Represents the possible type bounds for type references. |
7 | #[derive (Clone, Copy, Debug, Eq, PartialEq, Hash)] |
8 | pub enum TypeBounds { |
9 | /// The type is bounded by equality to the type index specified. |
10 | Eq(u32), |
11 | /// This type is a fresh resource type, |
12 | SubResource, |
13 | } |
14 | |
15 | impl Encode for TypeBounds { |
16 | fn encode(&self, sink: &mut Vec<u8>) { |
17 | match self { |
18 | Self::Eq(i: &u32) => { |
19 | sink.push(0x00); |
20 | i.encode(sink); |
21 | } |
22 | Self::SubResource => sink.push(0x01), |
23 | } |
24 | } |
25 | } |
26 | |
27 | /// Represents a reference to a type. |
28 | #[derive (Clone, Copy, Debug, Eq, PartialEq, Hash)] |
29 | pub enum ComponentTypeRef { |
30 | /// The reference is to a core module type. |
31 | /// |
32 | /// The index is expected to be core type index to a core module type. |
33 | Module(u32), |
34 | /// The reference is to a function type. |
35 | /// |
36 | /// The index is expected to be a type index to a function type. |
37 | Func(u32), |
38 | /// The reference is to a value type. |
39 | Value(ComponentValType), |
40 | /// The reference is to a bounded type. |
41 | Type(TypeBounds), |
42 | /// The reference is to an instance type. |
43 | /// |
44 | /// The index is expected to be a type index to an instance type. |
45 | Instance(u32), |
46 | /// The reference is to a component type. |
47 | /// |
48 | /// The index is expected to be a type index to a component type. |
49 | Component(u32), |
50 | } |
51 | |
52 | impl ComponentTypeRef { |
53 | /// Gets the export kind of the reference. |
54 | pub fn kind(&self) -> ComponentExportKind { |
55 | match self { |
56 | Self::Module(_) => ComponentExportKind::Module, |
57 | Self::Func(_) => ComponentExportKind::Func, |
58 | Self::Value(_) => ComponentExportKind::Value, |
59 | Self::Type(..) => ComponentExportKind::Type, |
60 | Self::Instance(_) => ComponentExportKind::Instance, |
61 | Self::Component(_) => ComponentExportKind::Component, |
62 | } |
63 | } |
64 | } |
65 | |
66 | impl Encode for ComponentTypeRef { |
67 | fn encode(&self, sink: &mut Vec<u8>) { |
68 | self.kind().encode(sink); |
69 | |
70 | match self { |
71 | Self::Module(idx: &u32) | Self::Func(idx: &u32) | Self::Instance(idx: &u32) | Self::Component(idx: &u32) => { |
72 | idx.encode(sink); |
73 | } |
74 | Self::Value(ty: &ComponentValType) => ty.encode(sink), |
75 | Self::Type(bounds: &TypeBounds) => bounds.encode(sink), |
76 | } |
77 | } |
78 | } |
79 | |
80 | /// An encoder for the import section of WebAssembly components. |
81 | /// |
82 | /// # Example |
83 | /// |
84 | /// ```rust |
85 | /// use wasm_encoder::{Component, ComponentTypeSection, PrimitiveValType, ComponentImportSection, ComponentTypeRef}; |
86 | /// |
87 | /// let mut types = ComponentTypeSection::new(); |
88 | /// |
89 | /// // Define a function type of `[string, string] -> string`. |
90 | /// types |
91 | /// .function() |
92 | /// .params( |
93 | /// [ |
94 | /// ("a" , PrimitiveValType::String), |
95 | /// ("b" , PrimitiveValType::String) |
96 | /// ] |
97 | /// ) |
98 | /// .result(PrimitiveValType::String); |
99 | /// |
100 | /// // This imports a function named `f` with the type defined above |
101 | /// let mut imports = ComponentImportSection::new(); |
102 | /// imports.import("f" , ComponentTypeRef::Func(0)); |
103 | /// |
104 | /// let mut component = Component::new(); |
105 | /// component.section(&types); |
106 | /// component.section(&imports); |
107 | /// |
108 | /// let bytes = component.finish(); |
109 | /// ``` |
110 | #[derive (Clone, Debug, Default)] |
111 | pub struct ComponentImportSection { |
112 | bytes: Vec<u8>, |
113 | num_added: u32, |
114 | } |
115 | |
116 | impl ComponentImportSection { |
117 | /// Create a new component import section encoder. |
118 | pub fn new() -> Self { |
119 | Self::default() |
120 | } |
121 | |
122 | /// The number of imports in the section. |
123 | pub fn len(&self) -> u32 { |
124 | self.num_added |
125 | } |
126 | |
127 | /// Determines if the section is empty. |
128 | pub fn is_empty(&self) -> bool { |
129 | self.num_added == 0 |
130 | } |
131 | |
132 | /// Define an import in the component import section. |
133 | pub fn import(&mut self, name: &str, ty: ComponentTypeRef) -> &mut Self { |
134 | encode_component_import_name(&mut self.bytes, name); |
135 | ty.encode(&mut self.bytes); |
136 | self.num_added += 1; |
137 | self |
138 | } |
139 | } |
140 | |
141 | impl Encode for ComponentImportSection { |
142 | fn encode(&self, sink: &mut Vec<u8>) { |
143 | encode_section(sink, self.num_added, &self.bytes); |
144 | } |
145 | } |
146 | |
147 | impl ComponentSection for ComponentImportSection { |
148 | fn id(&self) -> u8 { |
149 | ComponentSectionId::Import.into() |
150 | } |
151 | } |
152 | |
153 | /// Prior to WebAssembly/component-model#263 import and export names were |
154 | /// discriminated with a leading byte indicating what kind of import they are. |
155 | /// After that PR though names are always prefixed with a 0x00 byte. |
156 | /// |
157 | /// On 2023-10-28 in bytecodealliance/wasm-tools#1262 was landed to start |
158 | /// transitioning to "always lead with 0x00". That updated the validator/parser |
159 | /// to accept either 0x00 or 0x01 but the encoder wasn't updated at the time. |
160 | /// |
161 | /// On 2024-09-03 in bytecodealliance/wasm-tools#TODO this encoder was updated |
162 | /// to always emit 0x00 as a leading byte. |
163 | /// |
164 | /// This function corresponds with the `importname'` production in the |
165 | /// specification. |
166 | pub(crate) fn encode_component_import_name(bytes: &mut Vec<u8>, name: &str) { |
167 | bytes.push(0x00); |
168 | name.encode(sink:bytes); |
169 | } |
170 | |