inspect-rs 0.1.0

Universal introspection for Rust
Documentation
<div align="center">

# inspect-rs

**Universal introspection and semantic terminal rendering for Rust.**

[![Crates.io](https://img.shields.io/crates/v/inspect-rs.svg?style=flat-square&color=818cf8&labelColor=000000&logo=rust&logoColor=white)](https://crates.io/crates/inspect-rs)
[![Documentation](https://img.shields.io/docsrs/inspect-rs?style=flat-square&color=38bdf8&labelColor=000000&logo=docs.rs&logoColor=white)](https://docs.rs/inspect-rs)
[![MSRV](https://img.shields.io/badge/MSRV-1.85%20(2024)-fbbf24.svg?style=flat-square&labelColor=000000&logo=rust&logoColor=white)](https://blog.rust-lang.org/2025/02/20/Rust-1.85.0.html)
[![Safety](https://img.shields.io/badge/unsafe-forbid-34d399.svg?style=flat-square&labelColor=000000&logo=shield&logoColor=white)](https://github.com/programmersd21/inspect-rs)
[![Build](https://img.shields.io/badge/build-passing-6ee7b7.svg?style=flat-square&labelColor=000000&logo=githubactions&logoColor=white)](https://github.com/programmersd21/inspect-rs)
[![License](https://img.shields.io/badge/license-MIT%20%2F%20Apache--2.0-a78bfa.svg?style=flat-square&labelColor=000000)](#license)

<br />

<img src="assets/demo.png" alt="inspect-rs semantic terminal inspection demo" width="840" />

Inspect Rust values as traversable structured data without coupling your application<br />to a debugger, serializer, UI framework, or runtime reflection engine.

</div>

---

## Highlights

<table>
<tr>
<td width="50%">

### ✦ Zero-Copy & Lazy Traversal
Scalar values and strings borrow directly from target memory without eager allocations. Child structures evaluate on-demand via lightweight closures.

</td>
<td width="50%">

### ✦ Production Terminal Styling
Semantic syntax highlighting communicating structure—types, fields, enums, variants, and secrets. Automatic TTY, `NO_COLOR`, and `FORCE_COLOR` handling.

</td>
</tr>
<tr>
<td width="50%">

### ✦ Built-In Security Model
First-class support for `#[inspect(secret)]` (redacted to `[REDACTED]`) and `#[inspect(sensitive)]` PII classification. Secrets never leak into default logs.

</td>
<td width="50%">

### ✦ Memory & Resource Safety
Configurable limits for recursion depth, item truncation (`… N more`), string bounds, and cycle detection to neutralize traversal bombs.

</td>
</tr>
<tr>
<td width="50%">

### ✦ Strict Decoupling
`inspect-core` is 100% dependency-free with zero knowledge of terminal escapes. Styling lives strictly in `inspect-format`.

</td>
<td width="50%">

### ✦ 100% Safe Rust
`#![forbid(unsafe_code)]` enforced workspace-wide across every crate, macro, example, and test suite.

</td>
</tr>
</table>

---

## Quick Start

Add `inspect-rs` to your `Cargo.toml`:

```toml
[dependencies]
inspect-rs = "0.1"
```

Derive `Inspect` on your types and format them:

```rust
use inspect_rs::{format_tree, Inspect, InspectCx};

#[derive(Inspect)]
struct Server {
    host: String,
    port: u16,
    running: bool,
    #[inspect(secret)]
    api_key: String,
}

let server = Server {
    host: "127.0.0.1".to_string(),
    port: 8080,
    running: true,
    api_key: "sk_live_99a8b7c6d5e4f3".to_string(),
};

let mut cx = InspectCx::new();
println!("{}", format_tree(&server.inspect(&mut cx)));
```

### Output

```text
Server
├── host: "127.0.0.1"
├── port: 8080
├── running: true
└── api_key: [REDACTED]
```

> [!TIP]
> When stdout is connected to an interactive terminal, `format_tree` renders restrained, high-contrast semantic syntax highlighting. When redirected (`| less` or `> log.txt`) or when `NO_COLOR=1` is set, clean plain text is emitted automatically.

---

## Beautiful Terminal Output

`inspect-rs` includes a production-grade terminal rendering engine styled like a modern Rust compiler and developer tool—not a demo drenched in random ANSI colors.

### Semantic Color Roles

Colors communicate structural roles rather than arbitrary text:

| Role | Default Dark Palette | Semantic Purpose |
|---|---|---|
| **Type** | Warm Copper (`#E08A5A`) | Struct names, collection identifiers (`Server`, `Vec`) |
| **Field** | Soft Sky Blue (`#6EB4EB`) | Struct field names (`host`, `port`, `workers`) |
| **Variant** | Soft Lilac (`#B491E1`) | Enum variants (`Status::Running`, `Postgres`) |
| **Key** | Teal Cyan (`#69CDC3`) | Map keys (`"us-east-1"`, `"timeout"`) |
| **String** | Sage Green (`#8EC680`) | String literals with subdued quotes |
| **Number** | Warm Gold (`#EBC05F`) | Integer and float scalar values (`8080`, `3.14`) |
| **Boolean** | Soft Magenta (`#C387B9`) | Boolean flags (`true`, `false`) |
| **Punctuation** | Subdued Gray (`#737882`) | Branch glyphs (`├── `, `└── `), colons, quotes |
| **Sensitive** | Bold Crimson (`#EB5F5F`) | Redacted secrets (`[REDACTED]`) |
| **Truncated** | Dimmed Italic Amber (`#E1B44B`) | Truncation notices (`… 42 more`) |
| **Error** | Bold Red (`#F05555`) | Recursive cycles (`<cycle>`), error variants |

---

## Classic Theme Suite

`inspect-rs` provides 14 classic developer palettes calibrated for dark, light, high-contrast, and legacy terminals:

| Theme | Constructor | CLI / String Name | Aesthetic Profile |
|---|---|---|---|
| **Dark (Default)** | `Theme::dark()` | `"dark"`, `"default"` | Warm copper & soft slate for dark terminals |
| **Gruvbox** | `Theme::gruvbox()` | `"gruvbox"` | Iconic warm, earthy retro groove palette |
| **Nord** | `Theme::nord()` | `"nord"` | Arctic, cool bluish-slate palette |
| **Dracula** | `Theme::dracula()` | `"dracula"` | Vibrant dark theme with purple and cyan accents |
| **Catppuccin Mocha** | `Theme::catppuccin_mocha()` | `"catppuccin"`, `"catppuccin-mocha"` | Soft pastel comfort palette |
| **Tokyo Night** | `Theme::tokyo_night()` | `"tokyo-night"` | Neon dark city aesthetic inspired by Tokyo nightlife |
| **One Dark** | `Theme::one_dark()` | `"one-dark"`, `"onedark"` | Iconic Atom and VS Code editor palette |
| **Solarized Dark** | `Theme::solarized_dark()` | `"solarized-dark"` | Ethan Schoonover's precision dark palette |
| **Solarized Light** | `Theme::solarized_light()` | `"solarized-light"` | Precision Solarized light background palette |
| **Light** | `Theme::light()` | `"light"` | Crisp high-contrast palette for light backgrounds |
| **Monokai** | `Theme::monokai()` | `"monokai"` | Classic Sublime Text high-contrast palette |
| **Ayu Dark** | `Theme::ayu_dark()` | `"ayu-dark"`, `"ayu"` | Warm modern dark editor palette |
| **ANSI 16** | `Theme::ansi16()` | `"ansi16"`, `"ansi"` | Standard 4-bit ANSI for restricted terminals |
| **Monochrome** | `Theme::monochrome()` | `"monochrome"`, `"plain"` | Terminal effects (bold, dim, italic, underline) with zero color |

### Selecting Themes

```rust
use inspect_rs::{format_tree_with, Theme, TreeConfig};

// 1. Using a typed constructor
let config = TreeConfig::colored().with_theme(Theme::gruvbox());
println!("{}", format_tree_with(&inspected, config));

// 2. Dynamic lookup (case-insensitive, kebab-case or snake_case)
let theme = Theme::by_name("tokyo-night").unwrap_or_default();
let config = TreeConfig::colored().with_theme(theme);
println!("{}", format_tree_with(&inspected, config));
```

### Custom Themes via Builder

```rust
use inspect_rs::{AnsiColor, Style, StyleRole, Theme, TreeConfig};

let custom = Theme::dark()
    .with(StyleRole::Type, Style::new().bold().fg_ansi(AnsiColor::BrightYellow))
    .with(StyleRole::Field, Style::new().fg_ansi(AnsiColor::BrightCyan))
    .with(StyleRole::String, Style::new().fg_rgb(140, 230, 140));

let config = TreeConfig::colored().with_theme(custom);
```

---

## Controlling Colors & Terminal Modes

`inspect-rs` adheres to modern Unix CLI standards:

| Signal | Mechanism | Behavior |
|---|---|---|
| **`NO_COLOR`** | Environment variable (`NO_COLOR=1`) | Completely disables ANSI escapes (<https://no-color.org>) |
| **`FORCE_COLOR`** | Environment variable (`FORCE_COLOR=1`) | Forces ANSI color emission even when piped |
| **`TERM=dumb`** | Environment variable | Disables styling for dumb/minimal terminals |
| **TTY Detection** | `std::io::IsTerminal` | Disables color when redirecting to files or pipes |

```rust
use inspect_rs::{format_tree, format_tree_colored, format_tree_plain, ColorChoice, TreeConfig};

// Automatic detection (TTY + env vars)
let auto = format_tree(&inspected);

// Explicitly uncolored (guaranteed zero ANSI sequences)
let plain = format_tree_plain(&inspected);

// Explicitly colored (forces ANSI escapes)
let colored = format_tree_colored(&inspected);
```

---

## Derive Macro Attributes

Fine-tune how your structs and fields are exposed:

```rust
#[derive(Inspect)]
struct DatabaseConfig {
    host: String,
    port: u16,

    // Secrets are permanently masked in default renderers
    #[inspect(secret)]
    password: String,

    // Sensitive data marked with PII metadata
    #[inspect(sensitive)]
    admin_email: String,

    // Omit field entirely from inspection
    #[inspect(skip)]
    internal_cache_key: u64,

    // Custom display name for the field
    #[inspect(rename = "service_url")]
    url: String,
}
```

---

## Safety & Resource Limits

Prevent recursive cycles and inspection bombs from consuming unbounded CPU or memory:

```rust
use inspect_rs::{InspectCx, InspectLimits};

let limits = InspectLimits {
    max_depth: 12,           // Maximum tree nesting depth
    max_items: 50,           // Maximum elements per collection before truncation
    max_nodes: 5000,         // Global ceiling on total nodes visited
    max_string_length: 512,  // String clipping threshold
    max_bytes: 2048,         // Byte-slice display ceiling
};

let mut cx = InspectCx::with_limits(limits);
let inspected = large_structure.inspect(&mut cx);
```

Recursive structs automatically print `<cycle>` instead of causing a stack overflow.

---

## Architecture

`inspect-rs` is cleanly partitioned into a modular workspace:

```text
┌────────────────────────────────────────────────────────┐
│                    Your Application                    │
│             #[derive(Inspect)] / structs / enums       │
└───────────────────────────┬────────────────────────────┘
                            │ implements Inspect
┌────────────────────────────────────────────────────────┐
│                      inspect-core                      │
│   Inspect trait · ValueRef · InspectCx · Limits · AST  │
│              (Zero runtime dependencies)               │
└───────────────────────────┬────────────────────────────┘
                            │ borrows ValueRef
┌────────────────────────────────────────────────────────┐
│                     inspect-format                     │
│    TreeFormatter · Themes · StyleRoles · StyledWriter  │
│             (Optional "color" feature via anstyle)     │
└───────────────────────────┬────────────────────────────┘
                            │ re-exports facade
┌────────────────────────────────────────────────────────┐
│                       inspect-rs                       │
│       Convenience helpers: format_tree, Config, API    │
└────────────────────────────────────────────────────────┘
```

| Crate | Responsibility | Dependencies |
|---|---|---|
| [`inspect-core`]crates/inspect-core | Traits, borrowed value graph, context, cycle limits | **Zero** |
| [`inspect-derive`]crates/inspect-derive | Procedural macro `#[derive(Inspect)]` | `syn`, `quote`, `proc-macro2` |
| [`inspect-format`]crates/inspect-format | Tree rendering, themes, styling, stream writing | `anstyle` (optional) |
| [`inspect-rs`]crates/inspect | Top-level facade crate | Workspace members |

---

## Performance

`inspect-rs` is engineered for zero runtime overhead in production:

- **Zero Allocations for Scalars**: Numbers, booleans, and small values return value copies directly.
- **Borrowed Strings**: String slices borrow directly without reallocating.
- **Zero-Allocation Uncolored Path**: When color is disabled, `StyledWriter` skips styling logic and streams plain bytes directly to the output.
- **Direct Stream Writing**: Colored rendering emits ANSI sequences directly to the buffer without allocating intermediate strings.

Run the Criterion benchmark suite:

```bash
cargo bench
```

---

## Comparison

| Feature | `Debug` | `bevy_reflect` | `valuable` | `inspect-rs` |
|---|:---:|:---:|:---:|:---:|
| **Output Type** | Opaque String | Dynamic Types / Patching | Visitor Callbacks | **Structured Borrowed AST** |
| **Zero-Copy Scalars** |||| **** |
| **Lazy Child Traversal** |||| **** |
| **Secret Redaction** |||| **✓ (`#[inspect(secret)]`)** |
| **Resource Limits & Cycles** |||| **** |
| **Semantic Color Themes** |||| **✓ (14 classic themes)** |
| **Dependency-Free Core** |||| **✓ (0 dependencies)** |
| **Safe Rust** |||| **✓ (`forbid(unsafe_code)`)** |

---

## Examples

Run any of the built-in examples:

```bash
# Demo all 14 color themes sequentially
cargo run --example colored

# Demo a specific theme
cargo run --example colored -- gruvbox
cargo run --example colored -- nord
cargo run --example colored -- dracula
cargo run --example colored -- tokyo-night

# Basic usage
cargo run --example basic

# Struct and enum nested inspection
cargo run --example nested
cargo run --example enums

# Collections (Vec, HashMap, arrays)
cargo run --example collections

# Secrets and sensitive redaction
cargo run --example attributes
```

---

## MSRV & Edition

- **Edition**: Rust 2024
- **Minimum Supported Rust Version**: `1.85.0`
- **Safety**: `#![forbid(unsafe_code)]`

---

## License

Dual-licensed under either of:

- **Apache License, Version 2.0** ([LICENSE-APACHE]LICENSE-APACHE)
- **MIT License** ([LICENSE-MIT]LICENSE-MIT)

at your option.