wasm_smith/component/
encode.rs

1use std::borrow::Cow;
2
3use crate::core::{CompositeInnerType, CompositeType};
4
5use super::*;
6use wasm_encoder::{ComponentExportKind, ComponentOuterAliasKind, ExportKind};
7
8impl Component {
9    /// Encode this Wasm component into bytes.
10    pub fn to_bytes(&self) -> Vec<u8> {
11        self.encoded().finish()
12    }
13
14    fn encoded(&self) -> wasm_encoder::Component {
15        let mut component = wasm_encoder::Component::new();
16        for section in &self.sections {
17            section.encode(&mut component);
18        }
19        component
20    }
21}
22
23impl Section {
24    fn encode(&self, component: &mut wasm_encoder::Component) {
25        match self {
26            Self::Custom(sec) => sec.encode(component),
27            Self::CoreModule(module) => {
28                let bytes = module.to_bytes();
29                component.section(&wasm_encoder::RawSection {
30                    id: wasm_encoder::ComponentSectionId::CoreModule as u8,
31                    data: &bytes,
32                });
33            }
34            Self::CoreInstance(_) => todo!(),
35            Self::CoreType(sec) => sec.encode(component),
36            Self::Component(comp) => {
37                let bytes = comp.to_bytes();
38                component.section(&wasm_encoder::RawSection {
39                    id: wasm_encoder::ComponentSectionId::Component as u8,
40                    data: &bytes,
41                });
42            }
43            Self::Instance(_) => todo!(),
44            Self::Alias(_) => todo!(),
45            Self::Type(sec) => sec.encode(component),
46            Self::Canonical(sec) => sec.encode(component),
47            Self::Start(_) => todo!(),
48            Self::Import(sec) => sec.encode(component),
49            Self::Export(_) => todo!(),
50        }
51    }
52}
53
54impl CustomSection {
55    fn encode(&self, component: &mut wasm_encoder::Component) {
56        component.section(&wasm_encoder::CustomSection {
57            name: (&self.name).into(),
58            data: Cow::Borrowed(&self.data),
59        });
60    }
61}
62
63impl TypeSection {
64    fn encode(&self, component: &mut wasm_encoder::Component) {
65        let mut sec = wasm_encoder::ComponentTypeSection::new();
66        for ty in &self.types {
67            ty.encode(sec.ty());
68        }
69        component.section(&sec);
70    }
71}
72
73impl ImportSection {
74    fn encode(&self, component: &mut wasm_encoder::Component) {
75        let mut sec = wasm_encoder::ComponentImportSection::new();
76        for imp in &self.imports {
77            sec.import(&imp.name, imp.ty);
78        }
79        component.section(&sec);
80    }
81}
82
83impl CanonicalSection {
84    fn encode(&self, component: &mut wasm_encoder::Component) {
85        let mut sec = wasm_encoder::CanonicalFunctionSection::new();
86        for func in &self.funcs {
87            match func {
88                Func::CanonLift {
89                    func_ty,
90                    options,
91                    core_func_index,
92                } => {
93                    let options = translate_canon_opt(options);
94                    sec.lift(*core_func_index, *func_ty, options);
95                }
96                Func::CanonLower {
97                    options,
98                    func_index,
99                } => {
100                    let options = translate_canon_opt(options);
101                    sec.lower(*func_index, options);
102                }
103            }
104        }
105        component.section(&sec);
106    }
107}
108
109impl CoreTypeSection {
110    fn encode(&self, component: &mut wasm_encoder::Component) {
111        let mut sec = wasm_encoder::CoreTypeSection::new();
112        for ty in &self.types {
113            ty.encode(sec.ty());
114        }
115        component.section(&sec);
116    }
117}
118
119impl CoreType {
120    fn encode(&self, enc: wasm_encoder::ComponentCoreTypeEncoder<'_>) {
121        match self {
122            Self::Func(ty) => {
123                enc.core()
124                    .function(ty.params.iter().copied(), ty.results.iter().copied());
125            }
126            Self::Module(mod_ty) => {
127                let mut enc_mod_ty = wasm_encoder::ModuleType::new();
128                for def in &mod_ty.defs {
129                    match def {
130                        ModuleTypeDef::TypeDef(CompositeType {
131                            inner: CompositeInnerType::Func(func_ty),
132                            ..
133                        }) => {
134                            enc_mod_ty.ty().function(
135                                func_ty.params.iter().copied(),
136                                func_ty.results.iter().copied(),
137                            );
138                        }
139                        ModuleTypeDef::TypeDef(_) => {
140                            unimplemented!("non-func types in a component's module type")
141                        }
142                        ModuleTypeDef::OuterAlias { count, i, kind } => match kind {
143                            CoreOuterAliasKind::Type(_) => {
144                                enc_mod_ty.alias_outer_core_type(*count, *i);
145                            }
146                        },
147                        ModuleTypeDef::Import(imp) => {
148                            enc_mod_ty.import(
149                                &imp.module,
150                                &imp.field,
151                                crate::core::encode::translate_entity_type(&imp.entity_type),
152                            );
153                        }
154                        ModuleTypeDef::Export(name, ty) => {
155                            enc_mod_ty.export(name, crate::core::encode::translate_entity_type(ty));
156                        }
157                    }
158                }
159                enc.module(&enc_mod_ty);
160            }
161        }
162    }
163}
164
165impl Type {
166    fn encode(&self, enc: wasm_encoder::ComponentTypeEncoder<'_>) {
167        match self {
168            Self::Defined(ty) => {
169                ty.encode(enc.defined_type());
170            }
171            Self::Func(func_ty) => {
172                let mut f = enc.function();
173
174                f.params(func_ty.params.iter().map(|(name, ty)| (name.as_str(), *ty)));
175                f.result(func_ty.unnamed_result_ty());
176            }
177            Self::Component(comp_ty) => {
178                let mut enc_comp_ty = wasm_encoder::ComponentType::new();
179                for def in &comp_ty.defs {
180                    match def {
181                        ComponentTypeDef::Import(imp) => {
182                            enc_comp_ty.import(&imp.name, imp.ty);
183                        }
184                        ComponentTypeDef::CoreType(ty) => {
185                            ty.encode(enc_comp_ty.core_type());
186                        }
187                        ComponentTypeDef::Type(ty) => {
188                            ty.encode(enc_comp_ty.ty());
189                        }
190                        ComponentTypeDef::Export { name, url: _, ty } => {
191                            enc_comp_ty.export(name, *ty);
192                        }
193                        ComponentTypeDef::Alias(a) => {
194                            enc_comp_ty.alias(translate_alias(a));
195                        }
196                    }
197                }
198                enc.component(&enc_comp_ty);
199            }
200            Self::Instance(inst_ty) => {
201                let mut enc_inst_ty = wasm_encoder::InstanceType::new();
202                for def in &inst_ty.defs {
203                    match def {
204                        InstanceTypeDecl::CoreType(ty) => {
205                            ty.encode(enc_inst_ty.core_type());
206                        }
207                        InstanceTypeDecl::Type(ty) => {
208                            ty.encode(enc_inst_ty.ty());
209                        }
210                        InstanceTypeDecl::Export { name, url: _, ty } => {
211                            enc_inst_ty.export(name, *ty);
212                        }
213                        InstanceTypeDecl::Alias(a) => {
214                            enc_inst_ty.alias(translate_alias(a));
215                        }
216                    }
217                }
218                enc.instance(&enc_inst_ty);
219            }
220        }
221    }
222}
223
224impl DefinedType {
225    fn encode(&self, enc: wasm_encoder::ComponentDefinedTypeEncoder<'_>) {
226        match self {
227            Self::Primitive(ty) => enc.primitive(*ty),
228            Self::Record(ty) => {
229                enc.record(ty.fields.iter().map(|(name, ty)| (name.as_str(), *ty)));
230            }
231            Self::Variant(ty) => {
232                enc.variant(
233                    ty.cases
234                        .iter()
235                        .map(|(name, ty, refines)| (name.as_str(), *ty, *refines)),
236                );
237            }
238            Self::List(ty) => {
239                enc.list(ty.elem_ty);
240            }
241            Self::Tuple(ty) => {
242                enc.tuple(ty.fields.iter().copied());
243            }
244            Self::Flags(ty) => {
245                enc.flags(ty.fields.iter().map(|f| f.as_str()));
246            }
247            Self::Enum(ty) => {
248                enc.enum_type(ty.variants.iter().map(|v| v.as_str()));
249            }
250            Self::Option(ty) => {
251                enc.option(ty.inner_ty);
252            }
253            Self::Result(ty) => {
254                enc.result(ty.ok_ty, ty.err_ty);
255            }
256        }
257    }
258}
259
260fn translate_canon_opt(options: &[CanonOpt]) -> Vec<wasm_encoder::CanonicalOption> {
261    options
262        .iter()
263        .map(|o| match o {
264            CanonOpt::StringUtf8 => wasm_encoder::CanonicalOption::UTF8,
265            CanonOpt::StringUtf16 => wasm_encoder::CanonicalOption::UTF16,
266            CanonOpt::StringLatin1Utf16 => wasm_encoder::CanonicalOption::CompactUTF16,
267            CanonOpt::Memory(idx) => wasm_encoder::CanonicalOption::Memory(*idx),
268            CanonOpt::Realloc(idx) => wasm_encoder::CanonicalOption::Realloc(*idx),
269            CanonOpt::PostReturn(idx) => wasm_encoder::CanonicalOption::PostReturn(*idx),
270        })
271        .collect()
272}
273
274fn translate_alias(alias: &Alias) -> wasm_encoder::Alias<'_> {
275    match alias {
276        Alias::InstanceExport {
277            instance,
278            name,
279            kind,
280        } => wasm_encoder::Alias::InstanceExport {
281            instance: *instance,
282            name,
283            kind: match kind {
284                InstanceExportAliasKind::Module => ComponentExportKind::Module,
285                InstanceExportAliasKind::Component => ComponentExportKind::Component,
286                InstanceExportAliasKind::Instance => ComponentExportKind::Instance,
287                InstanceExportAliasKind::Func => ComponentExportKind::Func,
288                InstanceExportAliasKind::Value => ComponentExportKind::Value,
289            },
290        },
291        Alias::CoreInstanceExport {
292            instance,
293            name,
294            kind,
295        } => wasm_encoder::Alias::CoreInstanceExport {
296            instance: *instance,
297            name,
298            kind: match kind {
299                CoreInstanceExportAliasKind::Func => ExportKind::Func,
300                CoreInstanceExportAliasKind::Table => ExportKind::Table,
301                CoreInstanceExportAliasKind::Global => ExportKind::Global,
302                CoreInstanceExportAliasKind::Memory => ExportKind::Memory,
303                CoreInstanceExportAliasKind::Tag => ExportKind::Tag,
304            },
305        },
306        Alias::Outer { count, i, kind } => wasm_encoder::Alias::Outer {
307            count: *count,
308            index: *i,
309            kind: match kind {
310                OuterAliasKind::Module => ComponentOuterAliasKind::CoreModule,
311                OuterAliasKind::Component => ComponentOuterAliasKind::Component,
312                OuterAliasKind::Type(_) => ComponentOuterAliasKind::Type,
313                OuterAliasKind::CoreType(_) => ComponentOuterAliasKind::CoreType,
314            },
315        },
316    }
317}