diff --git a/README.md b/README.md index dd3f6d6..4ff28cb 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,110 @@ # Thespian + Fast & flexible actors for Zig, C & C++ applications To build: + ``` -./zig build +zig build ``` See `tests/*` for many interesting examples. +To run the tests: +``` +zig build test +``` + +--- + +## Architecture Overview + +Thespian is an actor framework where concurrent units ("instances") +communicate exclusively via message passing, with no shared mutable state. +Messages are encoded using **CBOR** (Concise Binary Object Representation). + +The library has three layers: + +1. **C++ core** - the primary implementation (`src/instance.cpp`, `src/executor_asio.cpp`, `src/hub.cpp`) +2. **C API** - a thin wrapper layer in `src/c/` exposing the C++ core to other languages +3. **Zig module** - `src/thespian.zig` wraps the C API into idiomatic Zig types with comptime features + +--- + +## Key Concepts + +**`context`** - the runtime environment. You create one, spawn actors into +it, then call `run()`. It owns the executor thread pool. + +**`instance` / actor** - each spawned actor is a `behaviour` (a +`std::function`) that registers a `receiver` to handle incoming +messages. Actors run on an executor. Currently the only executor provided +in this repo is one backed by ASIO. + +**`handle` / `pid`** - a reference to a live actor. In C++ this is +`thespian::handle`; in Zig it is `pid` (owned) or `pid_ref` (borrowed). +Sending to an expired handle is safe and fails gracefully. + +**`message`** - a CBOR-encoded byte buffer. Pattern matching uses +`extract`/`match` with a composable matcher DSL (`string`, `array`, `any`, +`more`, etc.). + +**`hub`** - a pub/sub broadcast actor. Subscribers receive all broadcasts; +supports filtering and Unix socket-based IPC. + +--- + +## I/O Primitives + +| Primitive | Purpose | +| -------------------------------- | ------------------------------------------------ | +| `timeout` | One-shot timer | +| `metronome` | Repeating timer | +| `signal` | OS signal handling | +| `tcp_acceptor` / `tcp_connector` | TCP networking | +| `unx_acceptor` / `unx_connector` | Unix domain sockets | +| `socket` | Raw FD-backed socket I/O | +| `file_descriptor` | Async wait on arbitrary file descriptors (posix) | +| `file_stream` | Async read/write on file handles (win32) | +| `subprocess` | Child process management (platform-specific) | + +### ⚠️ I/O Primitive Ownership - Critical Rule + +**Every I/O primitive is owned by the actor that was executing at the time +it was created.** Async completion messages from a primitive are delivered +only to that owning actor. There is no way to transfer ownership or +redirect delivery to a different actor after construction. + +A common mistake is to create an I/O primitive in one actor and then spawn +a separate "handler" actor, passing the primitive (or its handle) to it. +The handler will never receive any events - they will continue to be +delivered to the original actor that created the primitive. + +**The correct pattern:** the actor responsible for handling a primitive's +events must be the one that creates it. If you need a dedicated handler +actor, have it create its own primitives from within its own behaviour. + +--- + +## Ownership & Lifecycle + +- Zig's `pid` is `Owned` (must call `deinit()`); `pid_ref` is `Wrapped` + (borrowed, no deinit required) +- Actors can `trap()` exit signals and `link()` to other actors for supervision +- `spawn_link` ties an actor's lifetime to its parent + +--- + +## Build System + +- **Zig 0.15.2+** required +- Dependencies: `cbor` (CBOR codec), `asio` (ASIO network executor), + `tracy` (optional profiling via `-Denable_tracy=true`) +- Produces a static library `libthespian` and a Zig module +- Tests live in `test/` and cover both the C++ and Zig APIs + +--- + +## Misc + See DeepWiki for more documentation: [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/neurocyte/thespian)