Skip to content

Commit d460166

Browse files
committed
[wit-component] Add implements encoding support to wit-component
Update component encoding to use `name_world_key_with_item` at sites that produce component-level extern names, so that `implements` imports and exports are encoded as `[implements=<I>]L` in the binary format. Five call sites are changed from `name_world_key` to the implements-aware variant: import_map key construction, component export names, ImportedResourceDrop lookups, and both direct and indirect InterfaceFunc lookups.
1 parent 5f195a7 commit d460166

File tree

7 files changed

+223
-8
lines changed

7 files changed

+223
-8
lines changed

crates/wit-component/src/encoding.rs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,18 @@ impl<'a> EncodingState<'a> {
456456
}
457457
}
458458

459+
fn world_import_name(&self, key: &WorldKey) -> String {
460+
let resolve = &self.info.encoder.metadata.resolve;
461+
let world = &resolve.worlds[self.info.encoder.metadata.world];
462+
resolve.name_world_key_with_item(key, &world.imports[key])
463+
}
464+
465+
fn world_export_name(&self, key: &WorldKey) -> String {
466+
let resolve = &self.info.encoder.metadata.resolve;
467+
let world = &resolve.worlds[self.info.encoder.metadata.world];
468+
resolve.name_world_key_with_item(key, &world.exports[key])
469+
}
470+
459471
fn root_import_type_encoder(
460472
&mut self,
461473
interface: Option<InterfaceId>,
@@ -731,7 +743,7 @@ impl<'a> EncodingState<'a> {
731743
let world = &resolve.worlds[self.info.encoder.metadata.world];
732744

733745
for export_name in exports {
734-
let export_string = resolve.name_world_key(export_name);
746+
let export_string = self.world_export_name(export_name);
735747
match &world.exports[export_name] {
736748
WorldItem::Function(func) => {
737749
let ty = self
@@ -1785,7 +1797,7 @@ impl<'a> EncodingState<'a> {
17851797
self.materialize_wit_import(
17861798
shims,
17871799
for_module,
1788-
iface.map(|_| resolve.name_world_key(key)),
1800+
iface.map(|_| self.world_import_name(key)),
17891801
&format!("{name}_drop"),
17901802
key,
17911803
AbiVariant::GuestImport,
@@ -1955,7 +1967,7 @@ impl<'a> EncodingState<'a> {
19551967
Import::InterfaceFunc(key, _, name, abi) => self.materialize_wit_import(
19561968
shims,
19571969
for_module,
1958-
Some(resolve.name_world_key(key)),
1970+
Some(self.world_import_name(key)),
19591971
name,
19601972
key,
19611973
*abi,
@@ -2849,14 +2861,15 @@ impl<'a> Shims<'a> {
28492861
// metadata out of this `match` to the loop below to figure that
28502862
// out.
28512863
Import::InterfaceFunc(key, _, name, abi) => {
2864+
let wit_world = &resolve.worlds[world.encoder.metadata.world];
28522865
self.append_indirect_wit_func(
28532866
world,
28542867
for_module,
28552868
module,
28562869
field,
28572870
key,
28582871
name,
2859-
Some(resolve.name_world_key(key)),
2872+
Some(resolve.name_world_key_with_item(key, &wit_world.imports[key])),
28602873
*abi,
28612874
)?;
28622875
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ pub fn encode_world(resolve: &Resolve, world_id: WorldId) -> Result<ComponentTyp
7373

7474
// Encode the imports
7575
for (name, import) in world.imports.iter() {
76-
let name = resolve.name_world_key(name);
76+
let name = resolve.name_world_key_with_item(name, import);
7777
log::trace!("encoding import {name}");
7878
let ty = match import {
7979
WorldItem::Interface { id, .. } => {
@@ -98,7 +98,7 @@ pub fn encode_world(resolve: &Resolve, world_id: WorldId) -> Result<ComponentTyp
9898
}
9999
// Encode the exports
100100
for (name, export) in world.exports.iter() {
101-
let name = resolve.name_world_key(name);
101+
let name = resolve.name_world_key_with_item(name, export);
102102
log::trace!("encoding export {name}");
103103
let ty = match export {
104104
WorldItem::Interface { id, .. } => {

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ impl<'a> ComponentWorld<'a> {
248248
item: &WorldItem,
249249
required: &Required<'_>,
250250
) -> Result<()> {
251-
let name = resolve.name_world_key(name);
251+
let name = resolve.name_world_key_with_item(name, item);
252252
log::trace!("register import `{name}`");
253253
let import_map_key = match item {
254254
WorldItem::Function(_) | WorldItem::Type { .. } => None,
@@ -314,7 +314,7 @@ impl<'a> ComponentWorld<'a> {
314314
// set. This means that only types not defined by referenced exports
315315
// will get added here.
316316
for (name, item) in resolve.worlds[world].exports.iter() {
317-
log::trace!("add live world export `{}`", resolve.name_world_key(name));
317+
log::trace!("add live world export `{}`", resolve.name_world_key_with_item(name, item));
318318
let id = match item {
319319
WorldItem::Interface { id, .. } => id,
320320
WorldItem::Function(_) | WorldItem::Type { .. } => {

crates/wit-component/src/printing.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,17 @@ impl<O: Output> WitPrinter<O> {
468468
match name {
469469
WorldKey::Name(name) => {
470470
match item {
471+
WorldItem::Interface {
472+
id,
473+
implements: Some(_),
474+
..
475+
} => {
476+
// `import label: use-path;` syntax
477+
self.print_name_type(name, TypeKind::Other);
478+
self.output.str(": ");
479+
self.print_path_to_interface(resolve, *id, cur_pkg)?;
480+
self.output.semicolon();
481+
}
471482
WorldItem::Interface { id, .. } => {
472483
self.print_name_type(name, TypeKind::Other);
473484
self.output.str(": ");
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
(component
2+
(type (;0;)
3+
(component
4+
(type (;0;)
5+
(instance
6+
(type (;0;) (option string))
7+
(type (;1;) (func (param "key" string) (result 0)))
8+
(export (;0;) "get" (func (type 1)))
9+
(type (;2;) (func (param "key" string) (param "value" string)))
10+
(export (;1;) "set" (func (type 2)))
11+
)
12+
)
13+
(export (;0;) "foo:foo/store" (instance (type 0)))
14+
)
15+
)
16+
(export (;1;) "store" (type 0))
17+
(type (;2;)
18+
(component
19+
(type (;0;)
20+
(instance
21+
(type (;0;) (func (param "msg" string)))
22+
(export (;0;) "log" (func (type 0)))
23+
)
24+
)
25+
(export (;0;) "foo:foo/logger" (instance (type 0)))
26+
)
27+
)
28+
(export (;3;) "logger" (type 2))
29+
(type (;4;)
30+
(component
31+
(type (;0;)
32+
(component
33+
(type (;0;)
34+
(instance
35+
(type (;0;) (option string))
36+
(type (;1;) (func (param "key" string) (result 0)))
37+
(export (;0;) "get" (func (type 1)))
38+
(type (;2;) (func (param "key" string) (param "value" string)))
39+
(export (;1;) "set" (func (type 2)))
40+
)
41+
)
42+
(import "[implements=<foo:foo/store>]primary" (instance (;0;) (type 0)))
43+
(type (;1;)
44+
(instance
45+
(type (;0;) (option string))
46+
(type (;1;) (func (param "key" string) (result 0)))
47+
(export (;0;) "get" (func (type 1)))
48+
(type (;2;) (func (param "key" string) (param "value" string)))
49+
(export (;1;) "set" (func (type 2)))
50+
)
51+
)
52+
(import "[implements=<foo:foo/store>]backup" (instance (;1;) (type 1)))
53+
(type (;2;)
54+
(instance
55+
(type (;0;) (func (param "msg" string)))
56+
(export (;0;) "log" (func (type 0)))
57+
)
58+
)
59+
(import "foo:foo/logger" (instance (;2;) (type 2)))
60+
)
61+
)
62+
(export (;0;) "foo:foo/multi-import" (component (type 0)))
63+
)
64+
)
65+
(export (;5;) "multi-import" (type 4))
66+
(type (;6;)
67+
(component
68+
(type (;0;)
69+
(component
70+
(type (;0;)
71+
(instance
72+
(type (;0;) (option string))
73+
(type (;1;) (func (param "key" string) (result 0)))
74+
(export (;0;) "get" (func (type 1)))
75+
(type (;2;) (func (param "key" string) (param "value" string)))
76+
(export (;1;) "set" (func (type 2)))
77+
)
78+
)
79+
(export (;0;) "[implements=<foo:foo/store>]primary" (instance (type 0)))
80+
(type (;1;)
81+
(instance
82+
(type (;0;) (option string))
83+
(type (;1;) (func (param "key" string) (result 0)))
84+
(export (;0;) "get" (func (type 1)))
85+
(type (;2;) (func (param "key" string) (param "value" string)))
86+
(export (;1;) "set" (func (type 2)))
87+
)
88+
)
89+
(export (;1;) "[implements=<foo:foo/store>]backup" (instance (type 1)))
90+
)
91+
)
92+
(export (;0;) "foo:foo/multi-export" (component (type 0)))
93+
)
94+
)
95+
(export (;7;) "multi-export" (type 6))
96+
(type (;8;)
97+
(component
98+
(type (;0;)
99+
(component
100+
(type (;0;)
101+
(instance
102+
(type (;0;) (option string))
103+
(type (;1;) (func (param "key" string) (result 0)))
104+
(export (;0;) "get" (func (type 1)))
105+
(type (;2;) (func (param "key" string) (param "value" string)))
106+
(export (;1;) "set" (func (type 2)))
107+
)
108+
)
109+
(import "foo:foo/store" (instance (;0;) (type 0)))
110+
(type (;1;)
111+
(instance
112+
(type (;0;) (option string))
113+
(type (;1;) (func (param "key" string) (result 0)))
114+
(export (;0;) "get" (func (type 1)))
115+
(type (;2;) (func (param "key" string) (param "value" string)))
116+
(export (;1;) "set" (func (type 2)))
117+
)
118+
)
119+
(import "[implements=<foo:foo/store>]cache" (instance (;1;) (type 1)))
120+
)
121+
)
122+
(export (;0;) "foo:foo/mixed" (component (type 0)))
123+
)
124+
)
125+
(export (;9;) "mixed" (type 8))
126+
(@custom "package-docs" "\01{\22worlds\22:{\22multi-import\22:{\22docs\22:\22A world that imports the same interface multiple times under different\5cnplain names using the `implements` syntax.\22},\22multi-export\22:{\22docs\22:\22A world that exports the same interface multiple times.\22},\22mixed\22:{\22docs\22:\22A world with both implements imports and a normal interface import,\5cntesting that elaboration adds the dependency correctly.\22}}}")
127+
(@producers
128+
(processed-by "wit-component" "$CARGO_PKG_VERSION")
129+
)
130+
)
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package foo:foo;
2+
3+
interface store {
4+
get: func(key: string) -> option<string>;
5+
set: func(key: string, value: string);
6+
}
7+
8+
interface logger {
9+
log: func(msg: string);
10+
}
11+
12+
/// A world that imports the same interface multiple times under different
13+
/// plain names using the `implements` syntax.
14+
world multi-import {
15+
import primary: store;
16+
import backup: store;
17+
import logger;
18+
}
19+
20+
/// A world that exports the same interface multiple times.
21+
world multi-export {
22+
export primary: store;
23+
export backup: store;
24+
}
25+
26+
/// A world with both implements imports and a normal interface import,
27+
/// testing that elaboration adds the dependency correctly.
28+
world mixed {
29+
import store;
30+
import cache: store;
31+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package foo:foo;
2+
3+
interface store {
4+
get: func(key: string) -> option<string>;
5+
6+
set: func(key: string, value: string);
7+
}
8+
9+
interface logger {
10+
log: func(msg: string);
11+
}
12+
13+
/// A world that imports the same interface multiple times under different
14+
/// plain names using the `implements` syntax.
15+
world multi-import {
16+
import primary: store;
17+
import backup: store;
18+
import logger;
19+
}
20+
/// A world that exports the same interface multiple times.
21+
world multi-export {
22+
export primary: store;
23+
export backup: store;
24+
}
25+
/// A world with both implements imports and a normal interface import,
26+
/// testing that elaboration adds the dependency correctly.
27+
world mixed {
28+
import store;
29+
import cache: store;
30+
}

0 commit comments

Comments
 (0)