Skip to content

Commit eedded8

Browse files
Add free and clone utilities for WIT types. Add some runtime tests.
1 parent d2207b0 commit eedded8

10 files changed

Lines changed: 504 additions & 0 deletions

File tree

crates/d/src/lib.rs

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1463,6 +1463,27 @@ impl<'a> DInterfaceGenerator<'a> {
14631463
String::new()
14641464
}
14651465
}
1466+
1467+
fn needs_wit_free(&self, ty: Type) -> bool {
1468+
match ty {
1469+
Type::String => true,
1470+
Type::Id(id) => {
1471+
let typeinfo = &self.r#gen.types.get(id);
1472+
typeinfo.has_list || typeinfo.has_resource
1473+
}
1474+
_ => false,
1475+
}
1476+
}
1477+
1478+
fn can_have_wit_clone(&self, ty: Type) -> bool {
1479+
match ty {
1480+
Type::Id(id) => {
1481+
let typeinfo = &self.r#gen.types.get(id);
1482+
!typeinfo.has_own_handle
1483+
}
1484+
_ => true,
1485+
}
1486+
}
14661487
}
14671488

14681489
impl<'a> InterfaceGenerator<'a> for DInterfaceGenerator<'a> {
@@ -1516,6 +1537,34 @@ impl<'a> InterfaceGenerator<'a> for DInterfaceGenerator<'a> {
15161537
));
15171538
}
15181539

1540+
self.src.push_str("\nvoid witFree() {\n");
1541+
for field in &record.fields {
1542+
let lower_name = field.name.to_lower_camel_case();
1543+
let escaped_name = escape_d_identifier(&lower_name);
1544+
1545+
if self.needs_wit_free(field.ty) {
1546+
self.src.push_str(&format!("{escaped_name}.witFree;\n"));
1547+
}
1548+
}
1549+
self.src.push_str("}\n");
1550+
1551+
if self.can_have_wit_clone(Type::Id(id)) {
1552+
self.src
1553+
.push_str(&format!("\n{escaped_name} witClone() const {{\n"));
1554+
self.src
1555+
.push_str(&format!("{escaped_name} clone = void;\n"));
1556+
for field in &record.fields {
1557+
let lower_name = field.name.to_lower_camel_case();
1558+
let escaped_name = escape_d_identifier(&lower_name);
1559+
1560+
self.src.push_str(&format!(
1561+
"clone.{escaped_name} = this.{escaped_name}.witClone;\n"
1562+
));
1563+
}
1564+
self.src.push_str("return clone;\n");
1565+
self.src.push_str("}\n");
1566+
}
1567+
15191568
self.src.push_str("}\n");
15201569
}
15211570

@@ -1604,6 +1653,7 @@ impl<'a> InterfaceGenerator<'a> for DInterfaceGenerator<'a> {
16041653
));
16051654
self.src
16061655
.push_str("static private extern(C) void __import_drop(uint);\n\n");
1656+
self.src.push_str("alias witFree = drop;\n");
16071657

16081658
self.src.push_str(&format!(
16091659
"// TODO: make RAII? disable copy for the own
@@ -1619,6 +1669,9 @@ impl<'a> InterfaceGenerator<'a> for DInterfaceGenerator<'a> {
16191669
}}
16201670
16211671
@disable this();
1672+
1673+
void witFree() {{}}
1674+
Borrow witClone() const {{ return Borrow(__handle); }}
16221675
"
16231676
));
16241677

@@ -1753,6 +1806,7 @@ impl<'a> InterfaceGenerator<'a> for DInterfaceGenerator<'a> {
17531806
));
17541807
self.src
17551808
.push_str("static private extern(C) void __import_drop(uint);\n\n");
1809+
self.src.push_str("alias witFree = drop;\n");
17561810

17571811
self.src.push_str(&format!(
17581812
"// TODO: make RAII? disable copy for the own
@@ -1768,6 +1822,9 @@ impl<'a> InterfaceGenerator<'a> for DInterfaceGenerator<'a> {
17681822
17691823
@disable this();
17701824
1825+
void witFree() {{}}
1826+
Borrow witClone() const {{ return Borrow(__handle); }}
1827+
17711828
"
17721829
));
17731830

@@ -1935,6 +1992,47 @@ impl<'a> InterfaceGenerator<'a> for DInterfaceGenerator<'a> {
19351992
));
19361993
}
19371994
}
1995+
1996+
self.src.push_str("\nvoid witFree() {\n");
1997+
if self.needs_wit_free(Type::Id(id)) {
1998+
self.src.push_str("switch (_tag) with (Tag) {\n");
1999+
for case in &variant.cases {
2000+
let lower_case_name = case.name.to_lower_camel_case();
2001+
let escaped_lower_case_name = escape_d_identifier(&lower_case_name);
2002+
2003+
if case.ty.is_some() && self.needs_wit_free(case.ty.unwrap()) {
2004+
self.src.push_str(&format!(
2005+
"case {escaped_lower_case_name}: _get!(Tag.{escaped_lower_case_name}).witFree; break;\n",
2006+
));
2007+
}
2008+
}
2009+
self.src.push_str("default: break;\n");
2010+
self.src.push_str("}\n");
2011+
}
2012+
self.src.push_str("}\n");
2013+
2014+
if self.can_have_wit_clone(Type::Id(id)) {
2015+
self.src
2016+
.push_str(&format!("\n{escaped_name} witClone() const {{\n"));
2017+
self.src.push_str("final switch (_tag) {\n");
2018+
for case in &variant.cases {
2019+
let lower_case_name = case.name.to_lower_camel_case();
2020+
let escaped_lower_case_name = escape_d_identifier(&lower_case_name);
2021+
2022+
if case.ty.is_some() {
2023+
self.src.push_str(&format!(
2024+
"case Tag.{escaped_lower_case_name}: return _create!(Tag.{escaped_lower_case_name})(this._get!(Tag.{escaped_lower_case_name}).witClone); break;\n",
2025+
));
2026+
} else {
2027+
self.src.push_str(&format!(
2028+
"case Tag.{escaped_lower_case_name}: return _create!(Tag.{escaped_lower_case_name}); break;\n",
2029+
));
2030+
}
2031+
}
2032+
self.src.push_str("}\n");
2033+
self.src.push_str("}\n");
2034+
}
2035+
19382036
self.src.push_str("}\n");
19392037
}
19402038

crates/d/src/wit_common.d

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ struct WitList(T) {
3131
inout(T)[] asSlice() @trusted inout {
3232
return (ptr && length) ? ptr[0..length] : null;
3333
}
34+
35+
bool opEquals(in T[] other) const => this[] == other;
36+
size_t toHash() const => this[].hashOf;
3437
}
3538
auto witList(T : U[], U)(T slice) => WitList!U(slice);
3639

@@ -75,6 +78,8 @@ mixin template WitFlags(T) if (__traits(isUnsigned, T)) {
7578
result.opOpAssign!op(flags);
7679
return result;
7780
}
81+
82+
typeof(this) witClone() const { return this; }
7883
}
7984

8085

@@ -163,6 +168,14 @@ public:
163168
{ return _present ? _value : fallback(); }
164169
}
165170

171+
auto some(T)(T value) @safe @nogc nothrow {
172+
return Option!T.some(value);
173+
}
174+
175+
auto none(T)(T value) @safe @nogc nothrow {
176+
return Option!T.some(value);
177+
}
178+
166179
/// Based on Rust's Result
167180
@mustuse
168181
struct Result(T, E) {
@@ -230,6 +243,83 @@ public:
230243
}
231244

232245

246+
void witFree(T)(scope ref T val) if (__traits(isArithmetic, T)) {
247+
// no-op
248+
}
249+
T witClone(T)(in T val) if (__traits(isArithmetic, T)) {
250+
return val;
251+
}
252+
253+
void witFree(T : Option!U, U)(scope ref T val) {
254+
static if (!is(U == void)) if (val.isSome) val.unwrap.witFree;
255+
}
256+
T witClone(T : Option!U, U)(in T val) {
257+
if (val.isSome) {
258+
static if (!is(U == void)) {
259+
return T.some(val.unwrap.witClone);
260+
} else {
261+
return T.some;
262+
}
263+
} else {
264+
return T.none;
265+
}
266+
}
267+
268+
void witFree(T : Result!(U, V), U, V)(scope ref T val) {
269+
if (val.isErr) {
270+
static if (!is(V == void)) val.unwrapErr.witFree;
271+
} else {
272+
static if (!is(U == void)) val.unwrap.witFree;
273+
}
274+
}
275+
T witClone(T : Result!(U, V), U, V)(in T val) {
276+
if (val.isErr) {
277+
static if (!is(V == void)) {
278+
return T.err(val.unwrapErr.witClone);
279+
} else {
280+
return T.err;
281+
}
282+
} else {
283+
static if (!is(U == void)) {
284+
return T.ok(val.unwrap.witClone);
285+
} else {
286+
return T.ok;
287+
}
288+
}
289+
}
290+
291+
void witFree(T : WitList!U, U)(scope ref T val) {
292+
foreach (ref e; val) {
293+
e.witFree;
294+
}
295+
if (val.ptr && val.length) free(val.ptr);
296+
val = null;
297+
}
298+
T witClone(T : WitList!U, U)(in T val) {
299+
if (val.ptr == null || val.length == 0) return T(null);
300+
301+
auto clone = mallocSlice!U(val.length);
302+
303+
foreach (i, ref e; clone) {
304+
e = val[i].witClone;
305+
}
306+
307+
return clone.witList;
308+
}
309+
310+
void witFree(T : Tuple!U, U...)(scope ref T val) {
311+
static foreach (F; T.tupleof) {
312+
__traits(child, val, F).witFree;
313+
}
314+
}
315+
T witClone(T : Tuple!U, U...)(in T val) {
316+
T clone;
317+
static foreach (F; T.tupleof) {
318+
__traits(child, clone, F) = __traits(child, val, F).witClone;
319+
}
320+
return clone;
321+
}
322+
233323
package(wit):
234324

235325
extern(C) {
@@ -276,6 +366,20 @@ version (WitBindings_DummyLibc) {
276366
llvm_trap();
277367
while(true) {}
278368
}
369+
370+
private int memcmp(const void* ptr1, const void* ptr2, size_t size)
371+
{
372+
auto data1 = cast(const(ubyte)*)ptr1;
373+
auto data2 = cast(const(ubyte)*)ptr2;
374+
375+
foreach (i; 0..size) {
376+
auto b1 = data1[i];
377+
auto b2 = data2[i];
378+
if (b1 != b2) return b1-b2;
379+
}
380+
381+
return 0;
382+
}
279383
} else {
280384
void* malloc(size_t size);
281385
void* realloc(void* ptr, size_t newSize);

tests/runtime/common-types/leaf.d

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import wit.test.common.leaf;
2+
import wit.common;
3+
4+
@witExport("test:common/to-test", "wrap")
5+
R1 wrap(in F1 flag) {
6+
switch (flag.bits) with (F1) {
7+
case a.bits:
8+
return R1(1, flag);
9+
case b.bits:
10+
return R1(2, flag);
11+
default:
12+
assert(0);
13+
}
14+
}
15+
16+
@witExport("test:common/to-test", "var-f")
17+
V1 varF() {
18+
return V1.b(42);
19+
}
20+
21+
alias Exports = wit.test.common.leaf.Exports!(
22+
wrap,
23+
varF
24+
);
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import wit.test.common.middle;
2+
import wit.common;
3+
4+
import imps = wit.test.common.to_test.imports;
5+
6+
@witExport("test:common/to-test", "wrap")
7+
R1 wrap(in F1 flag) {
8+
return imps.wrap(flag);
9+
}
10+
11+
@witExport("test:common/to-test", "var-f")
12+
V1 varF() {
13+
return imps.varF;
14+
}
15+
16+
alias Exports = wit.test.common.middle.Exports!(
17+
wrap,
18+
varF
19+
);
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import wit.test.common.runner;
2+
import wit.common;
3+
4+
@witExport("$root", "run")
5+
void run() {
6+
R1 res = wrap(F1.a);
7+
assert(res.b == F1.a);
8+
assert(res.a == 1);
9+
10+
R1 res2 = wrap(F1.b);
11+
assert(res2.b == F1.b);
12+
assert(res2.a == 2);
13+
14+
V1 res3 = varF();
15+
assert(res3.isB);
16+
assert(res3.getB == 42);
17+
}
18+
19+
alias Exports = wit.test.common.runner.Exports!(
20+
run
21+
);

tests/runtime/demo/runner.d

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import wit.a.b.runner;
2+
import wit.common;
3+
4+
@witExport("$root", "run")
5+
void run() {
6+
x();
7+
}
8+
9+
alias Exports = wit.a.b.runner.Exports!(
10+
run
11+
);

tests/runtime/demo/test.d

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import wit.a.b.test;
2+
import wit.common;
3+
4+
@witExport("a:b/the-test", "x")
5+
void x() {
6+
}
7+
8+
alias Exports = wit.a.b.test.Exports!(
9+
x
10+
);

0 commit comments

Comments
 (0)