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