caraspace_export_macros 0.1.0

Procedural macros for the caraspace crate (SpytialDecorators derive).
Documentation

Caraspace

crates.io docs.rs PR checks License

You can prove memory safety at compile time. You can derive Hash, Ord, and Serialize from a single line. And yet, when you want to know the shape of the BTreeMap<NodeId, Vec<Edge>> your program just built, you reach for dbg! and start counting braces.

[src/main.rs:42:17] tree = RBTree {
    root: Some(
        RBNode { key: 38, color: Black, left: Some(RBNode { key: 19,
        color: Black, left: Some(RBNode { key: 12, color: Black, left:
        Some(RBNode { key: 8, color: Red, left: None, right: None }),
        right: None }), right: Some(RBNode { key: 31, color: Red, ...

You know what this is. You'd sketch it on paper in five seconds. The terminal won't.

#[derive(Debug)] is proof that Rust already knows how to walk your value. Caraspace refines that walk into a faithful diagram instead of nested text, and exposes it through the macro you already reach for:

- std::dbg!(tree)
+ caraspace::dbg!(tree)

stderr stays byte-identical. The browser opens an interactive diagram of the same value. caraspace::dbg! is a strict superset of std::dbg! — same calling convention, same return semantics, plus the picture.

use caraspace::{dbg, SpytialDecorators};
use serde::Serialize;

#[derive(Debug, Serialize, SpytialDecorators)]
#[attribute(field = "key")]
#[orientation(selector = "{x, y : Node | x->y in left}",  directions = ["left",  "below"])]
#[orientation(selector = "{x, y : Node | x->y in right}", directions = ["right", "below"])]
struct Node {
    key: u32,
    left: Option<Box<Node>>,
    right: Option<Box<Node>>,
}

let tree = build_tree();
let tree = dbg!(tree); // returns `tree` through; diagram opens in browser

Decorators describe what should hold about the layout, not how to render it. They're declarative constraints, attached to the type once, applied everywhere a value of that type appears. The progressive-refinement walkthrough shows how a flat graph clarifies into a red-black tree as constraints accumulate.

For the design philosophy and motivating examples, see Brown PLT's blog post: Diagramming Program Values by Spatial Refinement.

Install

[dependencies]
caraspace = "0.1"
serde = { version = "1", features = ["derive"] }

Reference

dbg! matches the std::dbg! calling convention:

Form Behavior
dbg!() Prints location to stderr (same as std::dbg!())
dbg!(x) Prints {:#?} + opens diagram, returns x through
dbg!(&x) Same, borrows
dbg!(a, b) Returns (a, b); one diagram tab per argument

Type requirements: Debug (already required by std::dbg!), plus Serialize and SpytialDecorators.

Environment variables:

Variable Effect
SPYTIAL_NO_OPEN=1 Skip browser launch; useful for cargo test and CI
SPYTIAL_OUTPUT_PATH Pin the HTML output to a specific path (default: random tempfile)

For library code, or anywhere you don't want stderr noise:

use caraspace::diagram;
diagram(&tree); // no stderr, no source location, doesn't move

Failures (serialization, file write, missing browser) never panic — they log a one-line warning to stderr and return. Use try_export_json_instance for the fallible Result-returning path.

Examples

cargo run --example dbg_basic     # smallest dbg! swap
cargo run --example demo          # decorator collection across nested structs
cargo run --example rbt           # progressive refinement of a red-black tree

Headless / Docker

docker build -t caraspace .
docker run --rm -p 8080:8080 caraspace          # default: rbt
docker run --rm -p 8080:8080 caraspace demo

Open http://localhost:8080/rust_viz_data.html. Browser launch is disabled inside the container (SPYTIAL_NO_OPEN=1).

Docs

Status

Version 0.1.0
MSRV Rust 1.80
OS macOS, Linux, Windows
License MIT or Apache-2.0

Contributing

See CONTRIBUTING.md. Bug reports and PRs welcome.

License

Dual-licensed under MIT or Apache 2.0, at your option.