Skip to content

Commit 1dda1bf

Browse files
resource_alias tests and brief README
1 parent f546d20 commit 1dda1bf

5 files changed

Lines changed: 266 additions & 2 deletions

File tree

crates/d/README.md

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,36 @@ $ wit-bindgen d [OPTIONS] <WIT>
1212

1313
See the output of `wit-bindgen help d` for available options.
1414

15-
-------
15+
## Output Structure
1616

17-
TODO: Flesh out fuller docs (ownership, more usage, examples, etc.)
17+
Running `wit-bindgen d` on a WIT world will produce a full package structure mirroring the organization of the WIT world and the interfaces it uses. The default output directory and root package are both `wit`.
18+
19+
`wit.common` holds some definitions used across the generated bindings (for e.g. `result`, `option`, `list`, etc.).
20+
21+
The generated file for the world will by default, `public import` all relavent definitions. More selective imports can be made by importing the appropriate modules corresponding to particular interfaces.
22+
23+
The module for the world `foo:bar/world` will be placed in `wit/foo/bar/world/package.d`. Anonymous interface import and exports for the world will emitted in `wit/foo/bar/world/{imports|exports}`.
24+
25+
Top-level interfaces will be output similarly to worlds. `foo:bar/interface` gets split across multiple modules in `wit/foo/bar/interface/*.d`. Type definitions that are agnostic to import or export (any records, tuples, lists, etc. that do not contain resource handles) will go in `/common.d`. Function imports and import-specific types go in `/imports.d`, and exports go in `/exports.d`
26+
27+
## Memory/Resource Management
28+
29+
Currently, all imports take in parameters as "borrowing" and return memory "owning", with some caveats due to resource handles.
30+
31+
Memory is managed on the C `malloc` heap. This assumption can be used in some cases to reduce copies when unecessary.
32+
33+
When giving parameters to imports, any `list` or `string` memory is NOT freed, and the caller retains ownership/responibility for it. However, the ownership rules of WIT mean that any owning resource handles are invalidated. The bindings will not automatically "consume" these for you, and you will have to zero them out (default init) yourself after the call to prevent double-free.
34+
35+
When receiving parameters to exports, `list` and `string` memory is automatically freed. You must copy this memory elsewhere to retain it past the end of the call. Resource handles are not dropped however, and BOTH owning and borrowing handles (e.g. `Res` and `Res.Borrow`) must be dropped. To drop a handle, use `witDrop`.
36+
37+
When receiving values from imports, you are in charge of freeing the memory and dropping resource handles after you are finished with it/them. `witFree` deeply frees all such memory, and `witDrop` is also deep.
38+
39+
When return values from exports, all memory must be on the WIT/C heap, so it can be reliably `free`d by the bindings. `witClone` deeply copies all `list`s and `string`s.
40+
41+
`scope(exit)` is a valuable tool in helping keep track of this.
42+
43+
In the future, changes may be made to help make this more automatic.
44+
45+
## Examples
46+
47+
It is recommended to peruse `tests/runtime` to find concrete examples of how to use the bindings.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import wit.test.resource_alias.runner;
2+
3+
import wit.test.resource_alias.e1.imports : a1 = a, Foo1 = Foo, X;
4+
import wit.test.resource_alias.e2.imports : a2 = a, Foo2 = Foo;
5+
6+
import wit.common;
7+
8+
@witExport("$root", "run")
9+
void run() {
10+
auto fooE1 = Foo1(
11+
x: X.makeNew(42)
12+
);
13+
14+
// consumed later
15+
16+
a1(fooE1);
17+
18+
auto fooE2 = Foo2(
19+
x: X.makeNew(7)
20+
);
21+
// consumed later
22+
23+
auto barE2 = Foo1(
24+
x: X.makeNew(8)
25+
);
26+
// consumed later
27+
28+
auto y = X.makeNew(8);
29+
scope(exit) y.witDrop;
30+
31+
a2(fooE2, barE2, y);
32+
}
33+
34+
alias Exports = wit.test.resource_alias.runner.Exports!(
35+
run
36+
);
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import wit.test.resource_alias.test;
2+
3+
import wit.test.resource_alias.e1.exports : Foo1 = Foo, X;
4+
import wit.test.resource_alias.e2.exports : Foo2 = Foo, Bar, Y;
5+
6+
import wit.common;
7+
8+
@witExport("test:resource-alias/e1", "x")
9+
struct XImpl {
10+
uint val;
11+
12+
@witExport("test:resource-alias/e1", "[constructor]x")
13+
static X constructor(uint v) {
14+
return X.makeNew((out typeof(this) self) {
15+
self.val = v;
16+
});
17+
}
18+
}
19+
20+
@witExport("test:resource-alias/e1", "a")
21+
WitList!X a1(ref scope Foo1 f) {
22+
// `f.x` consumed by return
23+
24+
immutable X[1] ret = [f.x];
25+
26+
return ret.witList.witClone;
27+
}
28+
29+
@witExport("test:resource-alias/e2", "a")
30+
WitList!Y a2(ref scope Foo2 f, ref scope Bar g, Y.Borrow h) {
31+
// `f.x` consumed by return
32+
// `f.g` consumed by return
33+
//scope(exit) h.witDrop;
34+
35+
immutable X[2] ret = [f.x, g.x];
36+
37+
return ret.witList.witClone;
38+
}
39+
40+
41+
alias Exports = wit.test.resource_alias.test.Exports!(
42+
XImpl,
43+
a1,
44+
a2
45+
);
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import wit.test.resource_alias_redux.runner;
2+
3+
import wit.test.resource_alias_redux.runner.imports.the_test : Thing1 = Thing;
4+
import wit.test.resource_alias_redux.resource_alias1.imports : Foo1 = Foo, Thing2 = Thing;
5+
import wit.test.resource_alias_redux.resource_alias2.imports : Foo2 = Foo;
6+
7+
import wit.common;
8+
9+
@witExport("$root", "run")
10+
void run() {
11+
auto thing1 = Thing.makeNew("Ni Hao".witList);
12+
scope(exit) thing1.witDrop;
13+
14+
{
15+
Thing1[1] things = [thing1];
16+
auto result = test(things.witList);
17+
thing1 = Thing1.init; // consumed
18+
scope(exit) result.witFree;
19+
assert(result.length == 1);
20+
21+
{
22+
auto str = result[0].get;
23+
scope(exit) str.witFree;
24+
25+
assert(str == "Ni Hao GuestThing GuestThing.get");
26+
}
27+
}
28+
29+
30+
auto thing2 = Thing2.makeNew("Ciao".witList);
31+
scope(exit) thing2.witDrop;
32+
33+
{
34+
auto result = a(Foo1(thing: thing2));
35+
thing2 = Thing2.init; // consumed
36+
scope(exit) result.witFree;
37+
assert(result.length == 1);
38+
39+
{
40+
auto str = result[0].get;
41+
scope(exit) str.witFree;
42+
43+
assert(str == "Ciao GuestThing GuestThing.get");
44+
}
45+
}
46+
47+
48+
auto thing3 = Thing2.makeNew("Ciao".witList);
49+
scope(exit) thing3.witDrop;
50+
auto thing4 = Thing2.makeNew("Aloha".witList);
51+
scope(exit) thing4.witDrop;
52+
53+
{
54+
auto result = b(Foo2(thing: thing3), Bar(thing: thing4));
55+
thing3 = Thing2.init; // consumed
56+
thing4 = Thing2.init; // consumed
57+
scope(exit) result.witFree;
58+
assert(result.length == 2);
59+
60+
{
61+
auto str = result[0].get;
62+
scope(exit) str.witFree;
63+
64+
assert(str == "Ciao GuestThing GuestThing.get");
65+
}
66+
67+
{
68+
auto str = result[1].get;
69+
scope(exit) str.witFree;
70+
71+
assert(str == "Aloha GuestThing GuestThing.get");
72+
}
73+
}
74+
}
75+
76+
alias Exports = wit.test.resource_alias_redux.runner.Exports!(
77+
run
78+
);
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import wit.test.resource_alias_redux.test;
2+
3+
import wit.test.resource_alias_redux.test.exports.the_test : Thing1 = Thing;
4+
import wit.test.resource_alias_redux.resource_alias1.exports : Foo1 = Foo, Thing2 = Thing;
5+
import wit.test.resource_alias_redux.resource_alias2.exports : Foo2 = Foo;
6+
import wit.common;
7+
8+
extern(C) void* malloc(size_t size);
9+
extern(C) void free(void* ptr);
10+
11+
char[] concat(in char[] a, in char[] b) {
12+
auto ptr = cast(char*)malloc(a.length + b.length);
13+
assert((a.length + b.length) == 0 || ptr);
14+
15+
if (!ptr) return null;
16+
17+
ptr[0..a.length] = a[];
18+
ptr[a.length..a.length+b.length] = b[];
19+
20+
return ptr[0..a.length+b.length];
21+
}
22+
23+
@witExport("test:resource-alias-redux/resource-alias1", "thing")
24+
struct ThingImpl {
25+
const(char)[] str;
26+
27+
@witExport("test:resource-alias-redux/resource-alias1", "[constructor]thing")
28+
static Thing1 constructor(in WitString msg) {
29+
return Thing1.makeNew((out typeof(this) self) {
30+
self.str = concat(msg, " GuestThing");
31+
});
32+
}
33+
34+
@witExport("test:resource-alias-redux/resource-alias1", "[method]thing.get")
35+
WitString get() {
36+
return concat(str, " GuestThing.get").witList; // no clone; already on C heap
37+
}
38+
}
39+
40+
@witExport("test:resource-alias-redux/resource-alias1", "a")
41+
WitList!Thing1 a(scope ref Foo1 f) {
42+
scope(exit) f.witDrop;
43+
44+
Thing1[1] things = [f.thing];
45+
f.thing = Thing1.init; // consumed
46+
47+
return things.witList.witClone;
48+
}
49+
50+
@witExport("test:resource-alias-redux/resource-alias2", "b")
51+
WitList!Thing2 b(scope ref Foo2 f, scope ref Bar g) {
52+
scope(exit) {
53+
f.witDrop;
54+
g.witDrop;
55+
}
56+
57+
Thing1[2] things = [f.thing, g.thing];
58+
f.thing = Thing2.init; // consumed
59+
g.thing = Thing2.init; // consumed
60+
61+
return things.witList.witClone;
62+
}
63+
64+
@witExport("the-test", "test")
65+
WitList!Thing1 test(scope ref WitList!Thing1 things) {
66+
return things.witClone;
67+
}
68+
69+
70+
alias Exports = wit.test.resource_alias_redux.test.Exports!(
71+
ThingImpl,
72+
a,
73+
b,
74+
test
75+
);

0 commit comments

Comments
 (0)