cellbook 0.1.2

Dynamic computational notebook environment in plain Rust
Documentation
<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

| Crate | Description |
|-------|-------------|
| `cellbook` | Core library with context store, cell registry, and macros |
| `cellbook-macros` | Proc macros (`#[cell]`, `cellbook!`) |
| `cargo-cellbook` | CLI for project scaffolding and runtime |