From 0bba42d2a2d9effba6552a67689c9767eacd6cb0 Mon Sep 17 00:00:00 2001 From: Ivan FB Date: Sun, 31 May 2026 12:14:39 +0200 Subject: [PATCH] docs(examples): Go example reads typed struct returns Echo/Complex/Schedule now return typed Go structs (EchoResponse, ComplexResponse, ScheduleResult); print their fields instead of an "ok" line. Co-Authored-By: Claude Opus 4.8 --- examples/timer/go_bindings/README.md | 14 +++++++------ examples/timer/go_bindings/example/main.go | 24 ++++++++++++---------- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/examples/timer/go_bindings/README.md b/examples/timer/go_bindings/README.md index b93ecfc..7021040 100644 --- a/examples/timer/go_bindings/README.md +++ b/examples/timer/go_bindings/README.md @@ -29,8 +29,9 @@ overwritten each time and `gofmt`-finalized. Each call deep-copies its arguments across the FFI thread, so the Go-side C allocations are freed (via `defer`) as soon as the call returns. String-returning -methods give back a Go `string`; struct-returning methods deliver their CBOR -encoding (decode it with a Go CBOR library if needed). +methods give back a Go `string`; **struct-returning methods give back a typed Go +struct** — the C-POD return is read into Go inside the result callback (delivered +via a `runtime/cgo.Handle`), so the caller never touches C memory. ## Build & run @@ -44,14 +45,15 @@ Expected output: ``` created timer version: nim-timer v0.1.0 -echo: ok (struct param round-tripped) -complex: ok (seq/option graph deep-copied) -schedule: ok (three struct params in one call) +echo: echoed="hello from Go" timerName="go-native-demo" +complex: itemCount=2 hasNote=true summary="received 2 messages, note=a note, retries=3" +schedule: jobId="go-native-demo:nightly" willRunCount=12 done ``` `Echo`, `Complex` and `Schedule` take `{.ffi.}` structs, slices and optionals -directly — previously these procs were skipped by the Go generator. +directly and return typed Go structs — previously these procs were skipped by +the Go generator. For the cross-process / cross-machine path (CBOR over a socket), see [`../ipc`](../ipc); a Go client could speak the same wire protocol using any Go diff --git a/examples/timer/go_bindings/example/main.go b/examples/timer/go_bindings/example/main.go index 4d07673..d6ce723 100644 --- a/examples/timer/go_bindings/example/main.go +++ b/examples/timer/go_bindings/example/main.go @@ -3,8 +3,8 @@ // The generated cgo package marshals each {.ffi.} struct param into its flat // C-POD form and passes it to the native ABI by value — so methods that take // structs, sequences and optionals (Echo, Complex, Schedule) are now callable -// directly with idiomatic Go types. String-returning calls (Version) come back -// as a Go string; struct-returning calls deliver their CBOR encoding. +// directly with idiomatic Go types. Struct-returning calls hand back a typed Go +// struct too (read out of the C-POD inside the result callback). package main import ( @@ -31,15 +31,16 @@ func main() { fmt.Printf("version: %s\n", v) } - // Struct param: EchoRequest { Message string; DelayMs int64 }. - if _, err := node.Echo(timer.EchoRequest{Message: "hello from Go", DelayMs: 5}); err != nil { + // Struct param + typed struct return: EchoResponse { Echoed; TimerName }. + if resp, err := node.Echo(timer.EchoRequest{Message: "hello from Go", DelayMs: 5}); err != nil { log.Printf("echo: %v", err) } else { - fmt.Println("echo: ok (struct param round-tripped)") + fmt.Printf("echo: echoed=%q timerName=%q\n", resp.Echoed, resp.TimerName) } - // Deeply nested: slice of structs, slice of strings, two optionals. - _, err = node.Complex(timer.ComplexRequest{ + // Deeply nested param + typed return: slice of structs, slice of strings, + // two optionals in; ComplexResponse { Summary; ItemCount; HasNote } out. + cresp, err := node.Complex(timer.ComplexRequest{ Messages: []timer.EchoRequest{ {Message: "one", DelayMs: 0}, {Message: "two", DelayMs: 0}, @@ -51,11 +52,12 @@ func main() { if err != nil { log.Printf("complex: %v", err) } else { - fmt.Println("complex: ok (seq/option graph deep-copied)") + fmt.Printf("complex: itemCount=%d hasNote=%v summary=%q\n", + cresp.ItemCount, cresp.HasNote, cresp.Summary) } - // Multiple struct params at once. - _, err = node.Schedule( + // Multiple struct params at once; ScheduleResult out. + sresp, err := node.Schedule( timer.JobSpec{Name: "nightly", Payload: []string{"x"}, Priority: 5}, timer.RetryPolicy{MaxAttempts: 3, BackoffMs: 100, RetryOn: []string{"timeout"}}, timer.ScheduleConfig{StartAtMs: 1000, IntervalMs: 5000, Jitter: intp(50)}, @@ -63,7 +65,7 @@ func main() { if err != nil { log.Printf("schedule: %v", err) } else { - fmt.Println("schedule: ok (three struct params in one call)") + fmt.Printf("schedule: jobId=%q willRunCount=%d\n", sresp.JobId, sresp.WillRunCount) } fmt.Println("done")