Skip to main content

wit_component/encoding/
wit.rs

1use crate::encoding::types::{TypeEncodingMaps, ValtypeEncoder, extern_name};
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        external_id: resolve.external_id_value(key, item).map(|s| s.into()),
133        version_suffix: None,
134    }
135}
136
137struct Encoder<'a> {
138    component: ComponentBuilder,
139    resolve: &'a Resolve,
140    package: PackageId,
141}
142
143impl Encoder<'_> {
144    fn run(&mut self) -> Result<()> {
145        // Encode all interfaces as component types and then export them.
146        for (name, &id) in self.resolve.packages[self.package].interfaces.iter() {
147            let component_ty = self.encode_interface(id)?;
148            let ty = self.component.type_component(Some(name), &component_ty);
149            self.component
150                .export(name, ComponentExportKind::Type, ty, None);
151        }
152
153        // For each `world` encode it directly as a component and then create a
154        // wrapper component that exports that component.
155        for (name, &world) in self.resolve.packages[self.package].worlds.iter() {
156            let component_ty = encode_world(self.resolve, world)?;
157
158            let world = &self.resolve.worlds[world];
159            let mut wrapper = ComponentType::new();
160            wrapper.ty().component(&component_ty);
161            let pkg = &self.resolve.packages[world.package.unwrap()];
162            wrapper.export(pkg.name.interface_id(name), ComponentTypeRef::Component(0));
163
164            let ty = self.component.type_component(Some(name), &wrapper);
165            self.component
166                .export(name, ComponentExportKind::Type, ty, None);
167        }
168
169        Ok(())
170    }
171
172    fn encode_interface(&mut self, id: InterfaceId) -> Result<ComponentType> {
173        // Build a set of interfaces reachable from this document, including the
174        // interfaces in the document itself. This is used to import instances
175        // into the component type we're encoding. Note that entire interfaces
176        // are imported with all their types as opposed to just the needed types
177        // in an interface for this document. That's done to assist with the
178        // decoding process where everyone's view of a foreign document agrees
179        // notably on the order that types are defined in to assist with
180        // roundtripping.
181        let mut interfaces = IndexSet::new();
182        self.add_live_interfaces(&mut interfaces, id);
183
184        // Seed the set of used names with all exported interfaces to ensure
185        // that imported interfaces choose different names as the import names
186        // aren't used during decoding.
187        let mut used_names = IndexSet::new();
188        for id in interfaces.iter() {
189            let iface = &self.resolve.interfaces[*id];
190            if iface.package == Some(self.package) {
191                let first = used_names.insert(iface.name.as_ref().unwrap().clone());
192                assert!(first);
193            }
194        }
195
196        let mut encoder = InterfaceEncoder::new(self.resolve);
197        for interface in interfaces {
198            encoder.interface = Some(interface);
199            let iface = &self.resolve.interfaces[interface];
200            let name = self.resolve.id_of(interface).unwrap();
201            if interface == id {
202                let idx = encoder.encode_instance(interface)?;
203                log::trace!("exporting self as {idx}");
204                encoder.outer.export(name, ComponentTypeRef::Instance(idx));
205            } else {
206                encoder.push_instance();
207                for (_, id) in iface.types.iter() {
208                    encoder.encode_valtype(self.resolve, &Type::Id(*id))?;
209                }
210                let instance = encoder.pop_instance();
211                let idx = encoder.outer.type_count();
212                encoder.outer.ty().instance(&instance);
213                encoder.import_map.insert(interface, encoder.instances);
214                encoder.instances += 1;
215                encoder.outer.import(name, ComponentTypeRef::Instance(idx));
216            }
217        }
218
219        encoder.interface = None;
220
221        Ok(encoder.outer)
222    }
223
224    /// Recursively add all live interfaces reachable from `id` into the
225    /// `interfaces` set, and then add `id` to the set.
226    fn add_live_interfaces(&self, interfaces: &mut IndexSet<InterfaceId>, id: InterfaceId) {
227        if interfaces.contains(&id) {
228            return;
229        }
230        for id in self.resolve.interface_direct_deps(id) {
231            self.add_live_interfaces(interfaces, id);
232        }
233        assert!(interfaces.insert(id));
234    }
235}
236
237struct InterfaceEncoder<'a> {
238    resolve: &'a Resolve,
239    outer: ComponentType,
240    ty: Option<InstanceType>,
241    type_encoding_maps: TypeEncodingMaps<'a>,
242    saved_maps: Option<TypeEncodingMaps<'a>>,
243    import_map: HashMap<InterfaceId, u32>,
244    outer_type_map: HashMap<TypeId, u32>,
245    instances: u32,
246    import_types: bool,
247    interface: Option<InterfaceId>,
248}
249
250impl InterfaceEncoder<'_> {
251    fn new(resolve: &Resolve) -> InterfaceEncoder<'_> {
252        InterfaceEncoder {
253            resolve,
254            outer: ComponentType::new(),
255            ty: None,
256            type_encoding_maps: Default::default(),
257            import_map: Default::default(),
258            outer_type_map: Default::default(),
259            instances: 0,
260            saved_maps: None,
261            import_types: false,
262            interface: None,
263        }
264    }
265
266    fn encode_instance(&mut self, interface: InterfaceId) -> Result<u32> {
267        self.push_instance();
268        let iface = &self.resolve.interfaces[interface];
269        let mut type_order = IndexSet::new();
270        for (_, id) in iface.types.iter() {
271            self.encode_valtype(self.resolve, &Type::Id(*id))?;
272            type_order.insert(*id);
273        }
274
275        // Sort functions based on whether or not they're associated with
276        // resources.
277        //
278        // This is done here to ensure that when a WIT package is printed as WIT
279        // then decoded, or if it's printed as Wasm then decoded, the final
280        // result is the same. When printing via WIT resource methods are
281        // attached to the resource types themselves meaning that they'll appear
282        // intermingled with the rest of the types, namely first before all
283        // other functions. The purpose of this sort is to perform a stable sort
284        // over all functions by shuffling the resource-related functions first,
285        // in order of when their associated resource was encoded, and putting
286        // freestanding functions last.
287        //
288        // Note that this is not actually required for correctness, it's
289        // basically here to make fuzzing happy.
290        let mut funcs = iface.functions.iter().collect::<Vec<_>>();
291        funcs.sort_by_key(|(_name, func)| match func.kind.resource() {
292            Some(id) => type_order.get_index_of(&id).unwrap(),
293            None => type_order.len(),
294        });
295
296        for (name, func) in funcs {
297            let ty = self.encode_func_type(self.resolve, func)?;
298            self.ty.as_mut().unwrap().export(
299                extern_name(name, func.external_id.as_deref()),
300                ComponentTypeRef::Func(ty),
301            );
302        }
303        let instance = self.pop_instance();
304        let idx = self.outer.type_count();
305        self.outer.ty().instance(&instance);
306        self.import_map.insert(interface, self.instances);
307        self.instances += 1;
308        Ok(idx)
309    }
310
311    fn push_instance(&mut self) {
312        assert!(self.ty.is_none());
313        assert!(self.saved_maps.is_none());
314        self.saved_maps = Some(mem::take(&mut self.type_encoding_maps));
315        self.ty = Some(InstanceType::default());
316    }
317
318    fn pop_instance(&mut self) -> InstanceType {
319        let maps = self.saved_maps.take().unwrap();
320        self.type_encoding_maps = maps;
321        mem::take(&mut self.ty).unwrap()
322    }
323}
324
325impl<'a> ValtypeEncoder<'a> for InterfaceEncoder<'a> {
326    fn defined_type(&mut self) -> (u32, ComponentDefinedTypeEncoder<'_>) {
327        match &mut self.ty {
328            Some(ty) => (ty.type_count(), ty.ty().defined_type()),
329            None => (self.outer.type_count(), self.outer.ty().defined_type()),
330        }
331    }
332    fn define_function_type(&mut self) -> (u32, ComponentFuncTypeEncoder<'_>) {
333        match &mut self.ty {
334            Some(ty) => (ty.type_count(), ty.ty().function()),
335            None => (self.outer.type_count(), self.outer.ty().function()),
336        }
337    }
338    fn export_type(&mut self, index: u32, name: ComponentExternName<'a>) -> Option<u32> {
339        match &mut self.ty {
340            Some(ty) => {
341                assert!(!self.import_types);
342                let ret = ty.type_count();
343                ty.export(name, ComponentTypeRef::Type(TypeBounds::Eq(index)));
344                Some(ret)
345            }
346            None => {
347                let ret = self.outer.type_count();
348                if self.import_types {
349                    self.outer
350                        .import(name, ComponentTypeRef::Type(TypeBounds::Eq(index)));
351                } else {
352                    self.outer
353                        .export(name, ComponentTypeRef::Type(TypeBounds::Eq(index)));
354                }
355                Some(ret)
356            }
357        }
358    }
359    fn export_resource(&mut self, name: ComponentExternName<'a>) -> u32 {
360        let type_ref = ComponentTypeRef::Type(TypeBounds::SubResource);
361        match &mut self.ty {
362            Some(ty) => {
363                assert!(!self.import_types);
364                ty.export(name, type_ref);
365                ty.type_count() - 1
366            }
367            None => {
368                if self.import_types {
369                    self.outer.import(name, type_ref);
370                } else {
371                    self.outer.export(name, type_ref);
372                }
373                self.outer.type_count() - 1
374            }
375        }
376    }
377    fn type_encoding_maps(&mut self) -> &mut TypeEncodingMaps<'a> {
378        &mut self.type_encoding_maps
379    }
380    fn interface(&self) -> Option<InterfaceId> {
381        self.interface
382    }
383    fn import_type(&mut self, owner: InterfaceId, id: TypeId) -> u32 {
384        let ty = &self.resolve.types[id];
385        let instance = self.import_map[&owner];
386        let outer_idx = *self.outer_type_map.entry(id).or_insert_with(|| {
387            let ret = self.outer.type_count();
388            self.outer.alias(Alias::InstanceExport {
389                instance,
390                name: ty.name.as_ref().unwrap(),
391                kind: ComponentExportKind::Type,
392            });
393            ret
394        });
395        match &mut self.ty {
396            Some(ty) => {
397                let ret = ty.type_count();
398                ty.alias(Alias::Outer {
399                    count: 1,
400                    index: outer_idx,
401                    kind: ComponentOuterAliasKind::Type,
402                });
403                ret
404            }
405            None => outer_idx,
406        }
407    }
408}