# tiny-actor Generic building blocks for CSP/actor-model concurrency, ported to TinyGo. Each type maps to a common inter-goroutine communication pattern, eliminating the per-actor boilerplate of defining request structs, response channels, and caller methods. ## Types | Type | Caller | Actor | Pattern | |------|--------|-------|---------| | `Func[Req, Resp]` | `Call(req) -> resp` | `msg.Req`, `msg.Reply(resp)` | function call | | `Query[Resp]` | `Call() -> resp` | `msg.Reply(resp)` | getter | | `Proc[Req]` | `Call(req)` | `msg.Req`, `msg.Done()` | setter / command | | `Signal` | `Call()` | `msg.Done()` | trigger / reset | | `Inbox[T]` | `Send(v)` / `TrySend(v)` | `<-i.Recv()` | fire-and-forget | | `Lifecycle` | `Stop()` | `<-Stopping()`, `defer MarkDone()` | shutdown | All synchronous types use unbuffered channels. The caller blocks until the actor processes the message. This eliminates races where a buffered write appears to succeed but the actor hasn't seen it yet. ## Example ```go import "git.smesh.lol/tiny-actor" type Counter struct { inc actor.Signal get actor.Query[int] actor.Lifecycle } func NewCounter() *Counter { c := &Counter{ inc: actor.NewSignal(), get: actor.NewQuery[int](), Lifecycle: actor.NewLifecycle(), } actor.Go(c.Lifecycle, c.run) return c } func (c *Counter) run() { var n int for { select { case <-c.Stopping(): return case msg := <-c.inc.Recv(): n++ msg.Done() case msg := <-c.get.Recv(): msg.Reply(n) } } } func (c *Counter) Inc() { c.inc.Call() } func (c *Counter) Get() int { return c.get.Call() } ``` ## TinyGo This is the TinyGo port of [actor](https://git.smesh.lol/actor). The API is unchanged and the package is pure Go: no cgo, no reflection, no sync primitives, no OS-specific code. It was ported and tested with TinyGo 0.43.0 on Go 1.25.3. The library needs goroutines, so the target must have a scheduler: - `wasip1` and `wasm` use the asyncify scheduler and run the tests as-is. - Most embedded boards default to the `tasks` scheduler and compile. - AVR boards default to `-scheduler=none` and cannot run actors. Enabling `tasks` there overflows the flash and RAM of the classic Arduino targets. Run the test suite: ```shell tinygo test -target=wasip1 ./... tinygo test -target=wasm ./... ``` `go test ./...` also passes; TinyGo is the primary target. ## Design Principles - **No sync primitives.** No mutexes, no atomics, no sync.Once. All coordination is via channels and select. - **Unbuffered by default.** Synchronous types guarantee happens-before: when Call returns, the actor has processed the message. Use Inbox for intentionally async paths. - **State ownership.** The actor goroutine owns all mutable state. Callers get copies via response channels, never references. - **Composable.** Embed the channel types you need. No framework, no interface to satisfy, no registration. ## When to use what - **Func** - caller needs a computed result based on arguments (map lookup, filtered query) - **Query** - caller needs current state, no arguments (get count, get config) - **Proc** - caller needs to mutate state and wait for confirmation (set value, record event) - **Signal** - caller needs to trigger an action and wait (reset, flush, increment) - **Inbox** - caller must not block (logging, metrics, notifications). Use TrySend to drop on backpressure. ## Architecture Guide This library implements the intra-domain actor patterns described in [Moxie Architecture Patterns](https://git.smesh.lol/moxie/blob/docs/MOXIE_ARCHITECTURE_PATTERNS.md) - specifically the actor loop (section 3.1), typed operation channels (section 3.2), the synchronous-mutation rule (section 3.3), and context-aware calls (section 3.6). The five channel types are a direct realization of the taxonomy from section 3.2. ## Family Same architecture, four implementations: - **actor** (Go) - `go get git.smesh.lol/actor` - **tiny-actor** (TinyGo) - `go get git.smesh.lol/tiny-actor` - **[pickle](https://git.smesh.lol/pickle)** (Rust) - `pickle = { git = "https://git.smesh.lol/pickle" }` - **[anneal](https://git.smesh.lol/anneal)** (TypeScript) - `npm install anneal` ## Install ``` go get git.smesh.lol/tiny-actor ``` ## License AGPL-3.0-or-later