<div style="text-align: center"><img src="https://raw.githubusercontent.com/dcompoze/cellbook/main/cellbook.svg" width="20%"></div>
# Cellbook
Dynamic computational notebook environment in plain Rust.
- Cells are defined as `async` functions with `#[cell]` annotations
- Cells are compiled as a `dylib` crate and dynamically reloaded on changes
- `cargo-cellbook` CLI utility provides a TUI runner and automatic reloader
- Cells have access to a shared store which retains the cell context across reloads
- Cell output is stored and can be viewed in the TUI runner
- Integrates with external applications to view images, plots, graphs, etc.
## Installation
```bash
cargo install cargo-cellbook
```
To create and run a new cellbook project use:
```bash
cargo cellbook init <project-name>
cd <project-name>
cargo cellbook run
```
## Notebook structure
The notebook consists of individual cells which are loaded in source order and the `cellbook!(Config::default())` invocation which sets up the notebook with configuration options.
```rust
use cellbook::{cell, cellbook, load, store, Config, Result};
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
struct Stats {
mean: f64,
count: usize,
}
#[cell]
async fn load_data() -> Result<()> {
let data = vec![1.0, 2.0, 3.0, 4.0, 5.0];
store!(data)?;
println!("Loaded {} values", data.len());
Ok(())
}
#[cell]
async fn compute_stats() -> Result<()> {
let data: Vec<f64> = load!(data)?;
let stats = Stats {
mean: data.iter().sum::<f64>() / data.len() as f64,
count: data.len(),
};
println!("Mean: {:.2}", stats.mean);
store!(stats)?;
Ok(())
}
cellbook!(Config::default());
```
## Context store
Cells can store persistent data in the shared store using `store!()`, `load!()`, `remove!()`, `consume!()` convenience macros.
Values in the store are serialized with [postcard](https://crates.io/crates/postcard), hence stored types must implement serde's `Serialize` and `Deserialize` traits.
```rust
// Store a value (variable name becomes the key)
store!(data)?;
// Store with explicit key
store!(my_key = some_value)?;
// Load a value (type has to be specified)
let data: Vec<f64> = load!(data)?;
// Remove a value from the store
remove!(data);
// Load and remove the value from the store
let data: Vec<f64> = consume!(data)?;
```
## Components
| `cellbook` | Core library with context store, cell registry, and macros |
| `cellbook-macros` | Proc macros (`#[cell]`, `cellbook!`) |
| `cargo-cellbook` | CLI for project scaffolding and runtime |