Skip to content

Commit 564157e

Browse files
authored
Remove v1 encoding support for WIT documents/worlds (#1781)
* Remove v1 encoding support for WIT documents/worlds This commit removes support for the "v1" encoding of WIT packages into WebAssembly. This was originally migrated to v2 in #1252 and v2 was enabled by default in #1274. This finishes the transition by removing support for creating the old encoding. * Fix fuzzer build * Update outdated comments
1 parent de9369c commit 564157e

7 files changed

Lines changed: 139 additions & 500 deletions

File tree

crates/wit-component/src/encoding/wit/v1.rs renamed to crates/wit-component/src/encoding/wit.rs

Lines changed: 133 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,30 @@ use std::mem;
66
use wasm_encoder::*;
77
use wit_parser::*;
88

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.
27+
pub 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+
933
/// Encodes the given `package` within `resolve` to a binary WebAssembly
1034
/// representation.
1135
///
@@ -41,6 +65,82 @@ pub fn encode_component(resolve: &Resolve, package: PackageId) -> Result<Compone
4165
Ok(encoder.component)
4266
}
4367

68+
/// Encodes a `world` as a component type.
69+
pub 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+
44144
struct Encoder<'a> {
45145
component: ComponentBuilder,
46146
resolve: &'a Resolve,
@@ -49,6 +149,34 @@ struct Encoder<'a> {
49149

50150
impl Encoder<'_> {
51151
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> {
52180
// Build a set of interfaces reachable from this document, including the
53181
// interfaces in the document itself. This is used to import instances
54182
// into the component type we're encoding. Note that entire interfaces
@@ -58,9 +186,7 @@ impl Encoder<'_> {
58186
// notably on the order that types are defined in to assist with
59187
// roundtripping.
60188
let mut interfaces = IndexSet::new();
61-
for (_, id) in self.resolve.packages[self.package].interfaces.iter() {
62-
self.add_live_interfaces(&mut interfaces, *id);
63-
}
189+
self.add_live_interfaces(&mut interfaces, id);
64190

65191
// Seed the set of used names with all exported interfaces to ensure
66192
// that imported interfaces choose different names as the import names
@@ -73,23 +199,15 @@ impl Encoder<'_> {
73199
assert!(first);
74200
}
75201
}
76-
for (name, _world) in self.resolve.packages[self.package].worlds.iter() {
77-
let first = used_names.insert(name.clone());
78-
assert!(first);
79-
}
80202

81-
// Encode all interfaces, foreign and local, into this component type.
82-
// Local interfaces get their functions defined as well and are
83-
// exported. Foreign interfaces are imported and only have their types
84-
// encoded.
85203
let mut encoder = InterfaceEncoder::new(self.resolve);
86204
for interface in interfaces {
87205
encoder.interface = Some(interface);
88206
let iface = &self.resolve.interfaces[interface];
89207
let name = self.resolve.id_of(interface).unwrap();
90-
log::trace!("encoding interface {name}");
91-
if iface.package == Some(self.package) {
208+
if interface == id {
92209
let idx = encoder.encode_instance(interface)?;
210+
log::trace!("exporting self as {idx}");
93211
encoder.outer.export(&name, ComponentTypeRef::Instance(idx));
94212
} else {
95213
encoder.push_instance();
@@ -104,21 +222,10 @@ impl Encoder<'_> {
104222
encoder.outer.import(&name, ComponentTypeRef::Instance(idx));
105223
}
106224
}
107-
encoder.interface = None;
108225

109-
for (name, world) in self.resolve.packages[self.package].worlds.iter() {
110-
let component_ty = encode_world(self.resolve, *world)?;
111-
let idx = encoder.outer.type_count();
112-
encoder.outer.ty().component(&component_ty);
113-
let id = self.resolve.packages[self.package].name.interface_id(name);
114-
encoder.outer.export(&id, ComponentTypeRef::Component(idx));
115-
}
226+
encoder.interface = None;
116227

117-
let ty = self.component.type_component(&encoder.outer);
118-
let id = self.resolve.packages[self.package].name.interface_id("wit");
119-
self.component
120-
.export(&id, ComponentExportKind::Type, ty, None);
121-
Ok(())
228+
Ok(encoder.outer)
122229
}
123230

124231
/// Recursively add all live interfaces reachable from `id` into the
@@ -317,79 +424,3 @@ impl<'a> ValtypeEncoder<'a> for InterfaceEncoder<'a> {
317424
&mut self.func_type_map
318425
}
319426
}
320-
321-
/// Encodes a `world` as a component type.
322-
pub fn encode_world(resolve: &Resolve, world_id: WorldId) -> Result<ComponentType> {
323-
let mut component = InterfaceEncoder::new(resolve);
324-
let world = &resolve.worlds[world_id];
325-
log::trace!("encoding world {}", world.name);
326-
327-
// This sort is similar in purpose to the sort below in
328-
// `encode_instance`, but different in its sort. The purpose here is
329-
// to ensure that when a document is either printed as WIT or
330-
// encoded as wasm that decoding from those artifacts produces the
331-
// same WIT package. Namely both encoding processes should encode
332-
// things in the same order.
333-
//
334-
// When printing worlds in WIT freestanding function imports are
335-
// printed first, then types. Resource functions are attached to
336-
// types which means that they all come last. Sort all
337-
// resource-related functions here to the back of the `imports` list
338-
// while keeping everything else in front, using a stable sort to
339-
// preserve preexisting ordering.
340-
let mut imports = world.imports.iter().collect::<Vec<_>>();
341-
imports.sort_by_key(|(_name, import)| match import {
342-
WorldItem::Function(f) => match f.kind {
343-
FunctionKind::Freestanding => 0,
344-
_ => 1,
345-
},
346-
_ => 0,
347-
});
348-
349-
// Encode the imports
350-
for (name, import) in imports {
351-
let name = resolve.name_world_key(name);
352-
log::trace!("encoding import {name}");
353-
let ty = match import {
354-
WorldItem::Interface { id, .. } => {
355-
component.interface = Some(*id);
356-
let idx = component.encode_instance(*id)?;
357-
ComponentTypeRef::Instance(idx)
358-
}
359-
WorldItem::Function(f) => {
360-
component.interface = None;
361-
let idx = component.encode_func_type(resolve, f)?;
362-
ComponentTypeRef::Func(idx)
363-
}
364-
WorldItem::Type(t) => {
365-
component.interface = None;
366-
component.import_types = true;
367-
component.encode_valtype(resolve, &Type::Id(*t))?;
368-
component.import_types = false;
369-
continue;
370-
}
371-
};
372-
component.outer.import(&name, ty);
373-
}
374-
// Encode the exports
375-
for (name, export) in world.exports.iter() {
376-
let name = resolve.name_world_key(name);
377-
log::trace!("encoding export {name}");
378-
let ty = match export {
379-
WorldItem::Interface { id, .. } => {
380-
component.interface = Some(*id);
381-
let idx = component.encode_instance(*id)?;
382-
ComponentTypeRef::Instance(idx)
383-
}
384-
WorldItem::Function(f) => {
385-
component.interface = None;
386-
let idx = component.encode_func_type(resolve, f)?;
387-
ComponentTypeRef::Func(idx)
388-
}
389-
WorldItem::Type(_) => unreachable!(),
390-
};
391-
component.outer.export(&name, ty);
392-
}
393-
394-
Ok(component.outer)
395-
}

crates/wit-component/src/encoding/wit/mod.rs

Lines changed: 0 additions & 58 deletions
This file was deleted.

0 commit comments

Comments
 (0)