sprite-core 0.1.5

Sprite Engine — a fault-tolerant actor runtime for Rust
Documentation
![SpriteEngine Logo](image.jpg%20(1)%20(1).png)

<div align="center">

  <h1>Sprite Engine</h1>

  <p><strong>A fault-tolerant actor runtime for Rust. Like React, but for concurrent systems.</strong></p>

  [On Crates](https://crates.io/crates/sprite-core)

  <p>
    <a href="https://www.rust-lang.org"><img src="https://img.shields.io/badge/Rust-2021-orange?style=for-the-badge&logo=rust&logoColor=white" alt="Rust 2021"/></a>
    <a href="LICENSE"><img src="https://img.shields.io/badge/License-Apache_2.0-blue?style=for-the-badge&logo=apache" alt="License Apache 2.0"/></a>
    <a href="https://github.com/dragprog/sprite-engine"><img src="https://img.shields.io/badge/Build-Passing-brightgreen?style=for-the-badge&logo=github-actions" alt="Build Passing"/></a>
    <a href="https://github.com/dragprog/sprite-engine"><img src="https://img.shields.io/badge/Fault_Tolerance-100%25-success?style=for-the-badge" alt="Fault Tolerance 100%"/></a>
    <a href="https://github.com/dragprog/sprite-engine"><img src="https://img.shields.io/badge/Recovery-<50ns-violet?style=for-the-badge" alt="Recovery <50ns"/></a>
  </p>
</div>

---

## ⚡ What is Sprite?

Sprite is a **Rust library** for building fault-tolerant, concurrent actor systems with a clean, declarative API inspired by React.

Instead of writing complex supervision trees and manual error handling, you write **actor components** — pure setup closures that declare state, message handlers, and children. If an actor panics, Sprite automatically resurrects it in **under 50 nanoseconds** with its state intact.

---

## 🚀 Quick Start

```rust
use sprite_core::{Engine, Message};

fn main() {
    let engine = Engine::new();

    let counter = engine.spawn("counter", |ctx| {
        // Like React's useState — survives crashes
        let count = ctx.use_state("count", 0i64);

        ctx.on_message(move |msg| {
            if msg == "inc" {
                count.update(|c| c + 1);
                println!("count = {}", count.get());
            }
        });
    });

    counter.send(Message::text("inc"));
    counter.send(Message::text("inc"));
}
```

---

## 🧩 Core Concepts

| Concept | React Equivalent | What it does |
|---|---|---|
| `Engine` | `createRoot` | The runtime that mounts and manages actors |
| `engine.spawn(name, \|ctx\| { ... })` | `<Component />` | Creates an actor from a setup closure |
| `ctx.use_state(key, initial)` | `useState` | Declares typed state that survives crashes |
| `ctx.use_scratch(initial)` | `useRef` | Ephemeral value wiped on recovery |
| `ctx.on_message(\|msg\| { ... })` | `onClick` / event handler | Registers a message handler |
| `ctx.on_panic(\| \| { ... })` | `componentDidCatch` | Runs after each panic recovery |
| `ctx.on_mount(\| \| { ... })` | `useEffect([], ...)` | Runs once on first start |
| `ctx.on_unmount(\| \| { ... })` | cleanup function | Runs on graceful shutdown |
| `ctx.spawn(name, ...)` | child components | Spawns nested actors |
| `ctx.send_to(id, msg)` | props callback | Sends a message to another actor |
| `ctx.send_named(name, msg)` || Sends to a named actor |
| `ctx.poll()` || Non-blocking message check |
| `ctx.sleep(dur)` || Yield without blocking thread |
| `Handle::send(msg)` | `setState` / props | Sends a message to an actor |
| `Handle::send_msg(any)` || Send any `IntoMessage` type |
| `Handle::request(msg, timeout)` | `fetch` | Request/response pattern |

---

## 🔥 Fault Tolerance

```
     [ Panic in Actor ]
   catch_unwind catches it     (~0.05ms)
   Arena reset                  (~1ns)
   State already intact         (0ns — lives in shared store)
   Setup closure re-runs        (~1ms)
   Actor Fully Restored         (< 50ns for recovery core)
```

State created via `use_state` lives in a shared store outside the actor thread, so it **survives panics automatically**. The actor's scratch allocations (via `bumpalo`) are reset, but your data is safe.

---

## 🛡️ Circuit Breaker

If an actor panics more than **10 times in 5 seconds**, Sprite trips a circuit breaker and halts it — preventing infinite crash loops.

```rust
engine.spawn("fragile", |ctx| {
    ctx.on_message(|_| panic!("always"));
    // After 10 recoveries, this actor stops.
});
```

---

## 📦 Installation

```toml
[dependencies]
sprite-core = { git = "https://github.com/dragprog/sprite-engine" }
```

---

## 🏗️ Advanced Examples

### Actor Pool (load balancing)

```rust
use sprite_core::{Engine, Message, Pool};

let engine = Engine::new();
let pool = Pool::new(&engine, "worker", 4, |ctx| {
    ctx.on_message(|task| {
        println!("Worker {} processing: {:?}", ctx.id(), task);
    });
});

for i in 0..100 {
    pool.send(Message::int(i));
}
```

### Broadcast

```rust
engine.broadcast(Message::text("shutdown"));
```

### Named Actors

```rust
engine.spawn("logger", |ctx| {
    ctx.on_message(|msg| println!("{:?}", msg));
});

engine.send_named("logger", Message::text("hello"));
assert_eq!(engine.lookup("logger"), Some(id));
```

### Timer

```rust
use sprite_core::Timer;
use std::time::Duration;

Timer::send_after(handle.tx.clone(), Duration::from_secs(5), Message::text("timeout"));
```

### Builder API

```rust
use sprite_core::{Engine, ActorBuilder};

let handle = ActorBuilder::new("worker", |ctx| {
    ctx.on_message(|msg| { /* ... */ });
})
.arena_size(1024 * 128)
.max_recoveries(5)
.recovery_window(Duration::from_secs(10))
.spawn(&engine);
```

---

## 🧪 Running Tests

```bash
git clone https://github.com/dragprog/sprite-engine.git
cd sprite-engine
cargo test --workspace
cargo bench --bench recovery_speed
cargo bench --bench mailbox_throughput
cargo run --example counter
cargo run --example pool
cargo run --example broadcast
```

---

## 📊 Benchmarks

| Benchmark | Target |
|---|---|
| `recovery_speed` | Panic → full restore |
| `mailbox_throughput` | Messages / second |

---

## 🤝 Contributing

1. Fork the repo (`git checkout -b feature/cool-thing`).
2. Keep the API surface minimal and ergonomic.
3. Ensure tests pass (`cargo test`).
4. Submit a PR with a concise breakdown.

---

## 📄 License

Distributed under the **Apache License 2.0**. See [`LICENSE`](LICENSE) for details.