wit_component/encoding/
wit.rs

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