Skip to main content

wit_component/encoding/
wit.rs

1use crate::encoding::types::{TypeEncodingMaps, ValtypeEncoder};
2use anyhow::Result;
3use indexmap::IndexSet;
4use std::collections::HashMap;
5use std::mem;
6use wasm_encoder::*;
7use wit_parser::*;
8
9/// Encodes the given `package` within `resolve` to a binary WebAssembly
10/// representation.
11///
12/// This function is the root of the implementation of serializing a WIT package
13/// into a WebAssembly representation. The wasm representation serves two
14/// purposes:
15///
16/// * One is to be a binary encoding of a WIT document which is ideally more
17///   stable than the WIT textual format itself.
18/// * Another is to provide a clear mapping of all WIT features into the
19///   component model through use of its binary representation.
20///
21/// The `resolve` provided is a set of packages and types and such and the
22/// `package` argument is an ID within the world provided. The documents within
23/// `package` will all be encoded into the binary returned.
24///
25/// The binary returned can be [`decode`d](crate::decode) to recover the WIT
26/// package provided.
27pub fn encode(resolve: &Resolve, package: PackageId) -> Result<Vec<u8>> {
28    let mut component = encode_component(resolve, package)?;
29    component.raw_custom_section(&crate::base_producers().raw_custom_section());
30    Ok(component.finish())
31}
32
33/// Encodes the given `package` within `resolve` to a binary WebAssembly
34/// representation.
35///
36/// This function is the root of the implementation of serializing a WIT package
37/// into a WebAssembly representation. The wasm representation serves two
38/// purposes:
39///
40/// * One is to be a binary encoding of a WIT document which is ideally more
41///   stable than the WIT textual format itself.
42/// * Another is to provide a clear mapping of all WIT features into the
43///   component model through use of its binary representation.
44///
45/// The `resolve` provided is a set of packages and types and such and the
46/// `package` argument is an ID within the world provided. The documents within
47/// `package` will all be encoded into the binary returned.
48///
49/// The binary returned can be [`decode`d](crate::decode) to recover the WIT
50/// package provided.
51pub fn encode_component(resolve: &Resolve, package: PackageId) -> Result<ComponentBuilder> {
52    let mut encoder = Encoder {
53        component: ComponentBuilder::default(),
54        resolve,
55        package,
56    };
57    encoder.run()?;
58
59    let package_metadata = PackageMetadata::extract(resolve, package);
60    encoder.component.custom_section(&CustomSection {
61        name: PackageMetadata::SECTION_NAME.into(),
62        data: package_metadata.encode()?.into(),
63    });
64
65    Ok(encoder.component)
66}
67
68/// Encodes a `world` as a component type.
69pub fn encode_world(resolve: &Resolve, world_id: WorldId) -> Result<ComponentType> {
70    let mut component = InterfaceEncoder::new(resolve);
71    let world = &resolve.worlds[world_id];
72    log::trace!("encoding world {}", world.name);
73
74    // Encode the imports
75    for (key, import) in world.imports.iter() {
76        log::trace!("encoding import {}", resolve.name_world_key(key));
77        let ty = match import {
78            WorldItem::Interface { id, .. } => {
79                component.interface = Some(*id);
80                let idx = component.encode_instance(*id)?;
81                ComponentTypeRef::Instance(idx)
82            }
83            WorldItem::Function(f) => {
84                component.interface = None;
85                let idx = component.encode_func_type(resolve, f)?;
86                ComponentTypeRef::Func(idx)
87            }
88            WorldItem::Type { id, .. } => {
89                component.interface = None;
90                component.import_types = true;
91                component.encode_valtype(resolve, &Type::Id(*id))?;
92                component.import_types = false;
93                continue;
94            }
95        };
96        component
97            .outer
98            .import(component_extern_name(resolve, key, import), ty);
99    }
100    // Encode the exports
101    for (key, export) in world.exports.iter() {
102        log::trace!("encoding export {}", resolve.name_world_key(key));
103        let ty = match export {
104            WorldItem::Interface { id, .. } => {
105                component.interface = Some(*id);
106                let idx = component.encode_instance(*id)?;
107                ComponentTypeRef::Instance(idx)
108            }
109            WorldItem::Function(f) => {
110                component.interface = None;
111                let idx = component.encode_func_type(resolve, f)?;
112                ComponentTypeRef::Func(idx)
113            }
114            WorldItem::Type { .. } => unreachable!(),
115        };
116        component
117            .outer
118            .export(component_extern_name(resolve, key, export), ty);
119    }
120
121    Ok(component.outer)
122}
123
124fn component_extern_name(
125    resolve: &Resolve,
126    key: &WorldKey,
127    item: &WorldItem,
128) -> wasm_encoder::ComponentExternName<'static> {
129    ComponentExternName {
130        name: resolve.name_world_key(key).into(),
131        implements: resolve.implements_value(key, item).map(|s| s.into()),
132    }
133}
134
135struct Encoder<'a> {
136    component: ComponentBuilder,
137    resolve: &'a Resolve,
138    package: PackageId,
139}
140
141impl Encoder<'_> {
142    fn run(&mut self) -> Result<()> {
143        // Encode all interfaces as component types and then export them.
144        for (name, &id) in self.resolve.packages[self.package].interfaces.iter() {
145            let component_ty = self.encode_interface(id)?;
146            let ty = self.component.type_component(Some(name), &component_ty);
147            self.component
148                .export(name, ComponentExportKind::Type, ty, None);
149        }
150
151        // For each `world` encode it directly as a component and then create a
152        // wrapper component that exports that component.
153        for (name, &world) in self.resolve.packages[self.package].worlds.iter() {
154            let component_ty = encode_world(self.resolve, world)?;
155
156            let world = &self.resolve.worlds[world];
157            let mut wrapper = ComponentType::new();
158            wrapper.ty().component(&component_ty);
159            let pkg = &self.resolve.packages[world.package.unwrap()];
160            wrapper.export(pkg.name.interface_id(name), ComponentTypeRef::Component(0));
161
162            let ty = self.component.type_component(Some(name), &wrapper);
163            self.component
164                .export(name, ComponentExportKind::Type, ty, None);
165        }
166
167        Ok(())
168    }
169
170    fn encode_interface(&mut self, id: InterfaceId) -> Result<ComponentType> {
171        // Build a set of interfaces reachable from this document, including the
172        // interfaces in the document itself. This is used to import instances
173        // into the component type we're encoding. Note that entire interfaces
174        // are imported with all their types as opposed to just the needed types
175        // in an interface for this document. That's done to assist with the
176        // decoding process where everyone's view of a foreign document agrees
177        // notably on the order that types are defined in to assist with
178        // roundtripping.
179        let mut interfaces = IndexSet::new();
180        self.add_live_interfaces(&mut interfaces, id);
181
182        // Seed the set of used names with all exported interfaces to ensure
183        // that imported interfaces choose different names as the import names
184        // aren't used during decoding.
185        let mut used_names = IndexSet::new();
186        for id in interfaces.iter() {
187            let iface = &self.resolve.interfaces[*id];
188            if iface.package == Some(self.package) {
189                let first = used_names.insert(iface.name.as_ref().unwrap().clone());
190                assert!(first);
191            }
192        }
193
194        let mut encoder = InterfaceEncoder::new(self.resolve);
195        for interface in interfaces {
196            encoder.interface = Some(interface);
197            let iface = &self.resolve.interfaces[interface];
198            let name = self.resolve.id_of(interface).unwrap();
199            if interface == id {
200                let idx = encoder.encode_instance(interface)?;
201                log::trace!("exporting self as {idx}");
202                encoder.outer.export(name, ComponentTypeRef::Instance(idx));
203            } else {
204                encoder.push_instance();
205                for (_, id) in iface.types.iter() {
206                    encoder.encode_valtype(self.resolve, &Type::Id(*id))?;
207                }
208                let instance = encoder.pop_instance();
209                let idx = encoder.outer.type_count();
210                encoder.outer.ty().instance(&instance);
211                encoder.import_map.insert(interface, encoder.instances);
212                encoder.instances += 1;
213                encoder.outer.import(name, ComponentTypeRef::Instance(idx));
214            }
215        }
216
217        encoder.interface = None;
218
219        Ok(encoder.outer)
220    }
221
222    /// Recursively add all live interfaces reachable from `id` into the
223    /// `interfaces` set, and then add `id` to the set.
224    fn add_live_interfaces(&self, interfaces: &mut IndexSet<InterfaceId>, id: InterfaceId) {
225        if interfaces.contains(&id) {
226            return;
227        }
228        for id in self.resolve.interface_direct_deps(id) {
229            self.add_live_interfaces(interfaces, id);
230        }
231        assert!(interfaces.insert(id));
232    }
233}
234
235struct InterfaceEncoder<'a> {
236    resolve: &'a Resolve,
237    outer: ComponentType,
238    ty: Option<InstanceType>,
239    type_encoding_maps: TypeEncodingMaps<'a>,
240    saved_maps: Option<TypeEncodingMaps<'a>>,
241    import_map: HashMap<InterfaceId, u32>,
242    outer_type_map: HashMap<TypeId, u32>,
243    instances: u32,
244    import_types: bool,
245    interface: Option<InterfaceId>,
246}
247
248impl InterfaceEncoder<'_> {
249    fn new(resolve: &Resolve) -> InterfaceEncoder<'_> {
250        InterfaceEncoder {
251            resolve,
252            outer: ComponentType::new(),
253            ty: None,
254            type_encoding_maps: Default::default(),
255            import_map: Default::default(),
256            outer_type_map: Default::default(),
257            instances: 0,
258            saved_maps: None,
259            import_types: false,
260            interface: None,
261        }
262    }
263
264    fn encode_instance(&mut self, interface: InterfaceId) -> Result<u32> {
265        self.push_instance();
266        let iface = &self.resolve.interfaces[interface];
267        let mut type_order = IndexSet::new();
268        for (_, id) in iface.types.iter() {
269            self.encode_valtype(self.resolve, &Type::Id(*id))?;
270            type_order.insert(*id);
271        }
272
273        // Sort functions based on whether or not they're associated with
274        // resources.
275        //
276        // This is done here to ensure that when a WIT package is printed as WIT
277        // then decoded, or if it's printed as Wasm then decoded, the final
278        // result is the same. When printing via WIT resource methods are
279        // attached to the resource types themselves meaning that they'll appear
280        // intermingled with the rest of the types, namely first before all
281        // other functions. The purpose of this sort is to perform a stable sort
282        // over all functions by shuffling the resource-related functions first,
283        // in order of when their associated resource was encoded, and putting
284        // freestanding functions last.
285        //
286        // Note that this is not actually required for correctness, it's
287        // basically here to make fuzzing happy.
288        let mut funcs = iface.functions.iter().collect::<Vec<_>>();
289        funcs.sort_by_key(|(_name, func)| match func.kind.resource() {
290            Some(id) => type_order.get_index_of(&id).unwrap(),
291            None => type_order.len(),
292        });
293
294        for (name, func) in funcs {
295            let ty = self.encode_func_type(self.resolve, func)?;
296            self.ty
297                .as_mut()
298                .unwrap()
299                .export(name, ComponentTypeRef::Func(ty));
300        }
301        let instance = self.pop_instance();
302        let idx = self.outer.type_count();
303        self.outer.ty().instance(&instance);
304        self.import_map.insert(interface, self.instances);
305        self.instances += 1;
306        Ok(idx)
307    }
308
309    fn push_instance(&mut self) {
310        assert!(self.ty.is_none());
311        assert!(self.saved_maps.is_none());
312        self.saved_maps = Some(mem::take(&mut self.type_encoding_maps));
313        self.ty = Some(InstanceType::default());
314    }
315
316    fn pop_instance(&mut self) -> InstanceType {
317        let maps = self.saved_maps.take().unwrap();
318        self.type_encoding_maps = maps;
319        mem::take(&mut self.ty).unwrap()
320    }
321}
322
323impl<'a> ValtypeEncoder<'a> for InterfaceEncoder<'a> {
324    fn defined_type(&mut self) -> (u32, ComponentDefinedTypeEncoder<'_>) {
325        match &mut self.ty {
326            Some(ty) => (ty.type_count(), ty.ty().defined_type()),
327            None => (self.outer.type_count(), self.outer.ty().defined_type()),
328        }
329    }
330    fn define_function_type(&mut self) -> (u32, ComponentFuncTypeEncoder<'_>) {
331        match &mut self.ty {
332            Some(ty) => (ty.type_count(), ty.ty().function()),
333            None => (self.outer.type_count(), self.outer.ty().function()),
334        }
335    }
336    fn export_type(&mut self, index: u32, name: &'a str) -> Option<u32> {
337        match &mut self.ty {
338            Some(ty) => {
339                assert!(!self.import_types);
340                let ret = ty.type_count();
341                ty.export(name, ComponentTypeRef::Type(TypeBounds::Eq(index)));
342                Some(ret)
343            }
344            None => {
345                let ret = self.outer.type_count();
346                if self.import_types {
347                    self.outer
348                        .import(name, ComponentTypeRef::Type(TypeBounds::Eq(index)));
349                } else {
350                    self.outer
351                        .export(name, ComponentTypeRef::Type(TypeBounds::Eq(index)));
352                }
353                Some(ret)
354            }
355        }
356    }
357    fn export_resource(&mut self, name: &'a str) -> u32 {
358        let type_ref = ComponentTypeRef::Type(TypeBounds::SubResource);
359        match &mut self.ty {
360            Some(ty) => {
361                assert!(!self.import_types);
362                ty.export(name, type_ref);
363                ty.type_count() - 1
364            }
365            None => {
366                if self.import_types {
367                    self.outer.import(name, type_ref);
368                } else {
369                    self.outer.export(name, type_ref);
370                }
371                self.outer.type_count() - 1
372            }
373        }
374    }
375    fn type_encoding_maps(&mut self) -> &mut TypeEncodingMaps<'a> {
376        &mut self.type_encoding_maps
377    }
378    fn interface(&self) -> Option<InterfaceId> {
379        self.interface
380    }
381    fn import_type(&mut self, owner: InterfaceId, id: TypeId) -> u32 {
382        let ty = &self.resolve.types[id];
383        let instance = self.import_map[&owner];
384        let outer_idx = *self.outer_type_map.entry(id).or_insert_with(|| {
385            let ret = self.outer.type_count();
386            self.outer.alias(Alias::InstanceExport {
387                instance,
388                name: ty.name.as_ref().unwrap(),
389                kind: ComponentExportKind::Type,
390            });
391            ret
392        });
393        match &mut self.ty {
394            Some(ty) => {
395                let ret = ty.type_count();
396                ty.alias(Alias::Outer {
397                    count: 1,
398                    index: outer_idx,
399                    kind: ComponentOuterAliasKind::Type,
400                });
401                ret
402            }
403            None => outer_idx,
404        }
405    }
406}