Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 67 additions & 6 deletions crates/go/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -930,7 +930,7 @@ impl WorldGenerator for Go {
.collect::<Vec<_>>()
.join("\n");
let header = &format!(
"// Generated by `wit-bindgen` {version}. DO NOT EDIT!
"// Code generated by wit-bindgen {version}. DO NOT EDIT.
//
// This code was generated from the following packages:
{packages}
Expand Down Expand Up @@ -2994,16 +2994,21 @@ func (self *{camel}) SetHandle(handle int32) {{

func (self *{camel}) Drop() {{
handle := self.handle
if self.handle != 0 {{
self.handle = 0
if handle != 0 {{
// Dropping an own handle of a resource this component exports runs
// its destructor (`resourceDtor{camel}`), which clears the handle,
// unpins `self` and calls `OnDrop`.
resourceDrop{camel}(handle)
self.pinner.Unpin()
self.OnDrop()
}}
}}

func {camel}FromOwnHandle(handle int32) *{camel} {{
return (*{camel})(unsafe.Pointer(resourceRep{camel}(handle)))
self := (*{camel})(unsafe.Pointer(resourceRep{camel}(handle)))
// The handle we received is a new one in this component's table, so
// record it; `Drop` must release this handle, not the one previously
// handed out by `TakeHandle`.
self.handle = handle
return self
}}

func {camel}FromBorrowHandle(rep int32) *{camel} {{
Expand Down Expand Up @@ -3468,3 +3473,59 @@ struct FutureStreamDedup {
pkg_name: String,
mangled_name: String,
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn generated_files_have_go_generated_code_header() {
let mut resolve = Resolve::default();
let pkg = resolve
.push_str(
"test.wit",
r#"
package a:b;

interface i {
resource r {
constructor();
}
f: func(x: r);
}

world w {
import i;
export i;
}
"#,
)
.unwrap();
let world = resolve.select_world(&[pkg], Some("w")).unwrap();
let mut files = Files::default();
Opts {
format: Format::False,
..Opts::default()
}
.build()
.generate(&mut resolve, world, &mut files)
.unwrap();

// Go tools recognize generated code by a line matching
// `^// Code generated .* DO NOT EDIT\.$` (https://go.dev/s/generatedcode).
let mut checked = 0;
for (name, contents) in files.iter() {
if !name.ends_with(".go") {
continue;
}
let first = std::str::from_utf8(contents).unwrap().lines().next();
let first = first.unwrap_or_default();
assert!(
first.starts_with("// Code generated ") && first.ends_with(" DO NOT EDIT."),
"{name}: unexpected first line {first:?}"
);
checked += 1;
}
assert!(checked > 0);
}
}
22 changes: 22 additions & 0 deletions tests/runtime/resource-own-roundtrip/runner.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package export_wit_world

import (
"fmt"
test "wit_component/test_resource_own_roundtrip_to_test"
)

func Run() {
assertEqual(test.ConsumeBoth(test.MakeThing(1), test.MakeThing(2)), uint32(3))
assertEqual(test.NumDropped(), uint32(2))

a := test.MakeThing(3)
b := test.MakeThing(4)
assertEqual(test.ConsumeBoth(b, a), uint32(7))
assertEqual(test.NumDropped(), uint32(4))
}

func assertEqual[T comparable](a T, b T) {
if a != b {
panic(fmt.Sprintf("%v not equal to %v", a, b))
}
}
21 changes: 21 additions & 0 deletions tests/runtime/resource-own-roundtrip/runner.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
include!(env!("BINDINGS"));

use crate::test::resource_own_roundtrip::to_test::{consume_both, num_dropped, Thing};

struct Component;

export!(Component);

impl Guest for Component {
fn run() {
let a = Thing::new(1);
let b = Thing::new(2);
assert_eq!(consume_both(a, b), 3);
assert_eq!(num_dropped(), 2);

let a = Thing::new(3);
let b = Thing::new(4);
assert_eq!(consume_both(b, a), 7);
assert_eq!(num_dropped(), 4);
}
}
31 changes: 31 additions & 0 deletions tests/runtime/resource-own-roundtrip/test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package export_test_resource_own_roundtrip_to_test

import (
"runtime"
)

type Thing struct {
pinner runtime.Pinner
handle int32
val uint32
}

var numDropped uint32 = 0

func (self *Thing) OnDrop() {
numDropped++
}

func MakeThing(v uint32) *Thing {
return &Thing{runtime.Pinner{}, 0, v}
}

func ConsumeBoth(a *Thing, b *Thing) uint32 {
defer a.Drop()
defer b.Drop()
return a.val + b.val
}

func NumDropped() uint32 {
return numDropped
}
38 changes: 38 additions & 0 deletions tests/runtime/resource-own-roundtrip/test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
include!(env!("BINDINGS"));

use exports::test::resource_own_roundtrip::to_test::{Guest, GuestThing, Thing};
use std::sync::atomic::{AtomicU32, Ordering};

static NUM_DROPPED: AtomicU32 = AtomicU32::new(0);

pub struct Test {}

export!(Test);

pub struct MyThing {
val: u32,
}

impl Drop for MyThing {
fn drop(&mut self) {
NUM_DROPPED.fetch_add(1, Ordering::SeqCst);
}
}

impl Guest for Test {
type Thing = MyThing;

fn consume_both(a: Thing, b: Thing) -> u32 {
a.get::<MyThing>().val + b.get::<MyThing>().val
}

fn num_dropped() -> u32 {
NUM_DROPPED.load(Ordering::SeqCst)
}
}

impl GuestThing for MyThing {
fn new(v: u32) -> Self {
Self { val: v }
}
}
24 changes: 24 additions & 0 deletions tests/runtime/resource-own-roundtrip/test.wit
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package test:resource-own-roundtrip;

// Own handles of an exported resource that are handed out and then passed
// back in. Passing two at once means the incoming handles cannot both reuse
// the slots handed out earlier, so the callee must drop the handles it
// actually received.
interface to-test {
resource thing {
constructor(v: u32);
}

consume-both: func(a: thing, b: thing) -> u32;
num-dropped: func() -> u32;
}

world test {
export to-test;
}

world runner {
import to-test;

export run: func();
}
Loading