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