mirror of
https://github.com/logos-messaging/nim-ffi.git
synced 2026-06-23 17:59:33 +00:00
5a: record {.ffiHost.} procs in a compile-time registry (FFIHostMeta /
ffiHostRegistry), populated by the macro, so generators can see host fns.
5b: the Go generator emits an idiomatic wrapper over the host C ABI:
- a single //export cgo trampoline backs every host fn; a cgo.Handle in
userData selects the Go closure;
- the closure runs on a fresh GOROUTINE so the FFI thread is never blocked
(the non-blocking contract), then answers via <lib>_host_complete by token;
- a per-host `Set<Name>(func(string) (string, error))` method registers it.
Validated end to end with `go run` (examples/host_demo): Go UseToken -> Nim
{.ffi.} handler -> await fetchToken {.ffiHost.} -> Go trampoline -> goroutine
runs the closure -> host_complete -> future resolves on the loop thread ->
"token[TOK-session]" back in Go. Timer's Go output is unchanged (no host fns);
its regenerated .h just gains the always-exported host ABI decls.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
38 lines
906 B
Go
38 lines
906 B
Go
// Go example for a {.ffiHost.} host callback.
|
|
//
|
|
// `fetchToken` is implemented HERE (the Go app) and registered with
|
|
// SetFetchToken. When we call UseToken, the Nim library calls back into this Go
|
|
// closure for a token — the closure runs on a goroutine the generated wrapper
|
|
// spawns (never blocking the FFI thread) and answers via host_complete.
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
|
|
hd "host_demo"
|
|
)
|
|
|
|
func main() {
|
|
node, err := hd.NewHost_demo()
|
|
if err != nil {
|
|
log.Fatalf("create: %v", err)
|
|
}
|
|
defer node.Destroy()
|
|
|
|
// The host's implementation of the {.ffiHost.} fetchToken.
|
|
node.SetFetchToken(func(key string) (string, error) {
|
|
return "TOK-" + key, nil
|
|
})
|
|
|
|
res, err := node.UseToken("session")
|
|
if err != nil {
|
|
log.Fatalf("useToken: %v", err)
|
|
}
|
|
fmt.Printf("result: %s\n", res)
|
|
if res != "token[TOK-session]" {
|
|
log.Fatalf("unexpected result: %q", res)
|
|
}
|
|
fmt.Println("OK")
|
|
}
|