toon-rust

Library Featured

Token-Oriented Object Notation (TOON) - a token-efficient JSON alternative for LLM prompts

Checked · Sources

Downloads
160,383
Dependents
67
Stars
190
Forks
28
Contributors
10
Commits
80
Latest release
0.7.0 ·

About

From the project README ·

TOON Format for Rust

Token-Oriented Object Notation (TOON) is a compact, human-readable format designed for passing structured data to Large Language Models with significantly reduced token usage.

This crate provides the official, spec-compliant Rust implementation of TOON, offering both a library (toon-format) and a full-featured command-line tool (toon).

toon-spec: 4.4 – this implementation targets TOON Specification v4.4.

Quick Example

JSON (16 tokens, 40 bytes):

{
  "users": [
    { "id": 1, "name": "Alice" },
    { "id": 2, "name": "Bob" }
  ]
}

TOON (13 tokens, 28 bytes) - 18.75% token savings:

users[2]{id,name}:
  1,Alice
  2,Bob

Features

  • Generic API: Works with any Serialize/Deserialize type - custom structs, enums, JSON values, and more
  • Spec-Compliant: Fully compliant with TOON Specification v4.4, including comment lines, keyed tabular form, and nested field groups
  • Safe & Performant: Built with safe, fast Rust
  • Powerful CLI: Full-featured command-line tool
  • Strict Validation: Enforces all spec rules (configurable)
  • Well-Tested: Comprehensive test suite with unit tests, spec fixtures, and real-world scenarios
Read the full README
Experimental Cargo Features
  • layout (experimental, off by default): Exposes decoder layout metadata (tabular vs list vs inline, declared [N] lengths, field descriptors) via decode_with_layout. Scoped to independent exploration of schema and tooling use cases (validators, formatters, linters); not part of the TOON specification and may evolve independently of the core decoder.

Installation

As a Library
cargo add toon-format
As a CLI Tool
cargo install toon-format

Library Usage

Basic Encode & Decode

The encode and decode functions work with any type implementing Serialize/Deserialize:

With custom structs:

use serde::{Serialize, Deserialize};
use toon_format::{encode_default, decode_default};

#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct User {
    name: String,
    age: u32,
    email: String,
}

fn main() -> Result<(), toon_format::ToonError> {
    let user = User {
        name: "Alice".to_string(),
        age: 30,
        email: "alice@example.com".to_string(),
    };

    // Encode to TOON
    let toon = encode_default(&user)?;
    println!("{}", toon);
    // Output:
    // name: Alice
    // age: 30
    // email: alice@example.com

    // Decode back to struct
    let decoded: User = decode_default(&toon)?;
    assert_eq!(user, decoded);

    Ok(())
}

With JSON values:

use serde_json::{json, Value};
use toon_format::{encode_default, decode_default};

fn main() -> Result<(), toon_format::ToonError> {
    let data = json!({
        "users": [
            {"id": 1, "name": "Alice"},
            {"id": 2, "name": "Bob"}
        ]
    });

    // Encode to TOON
    let toon_str = encode_default(&data)?;
    println!("{}", toon_str);
    // Output:
    // users[2]{id,name}:
    //   1,Alice
    //   2,Bob

    // Decode back to JSON
    let decoded: Value = decode_default(&toon_str)?;
    assert_eq!(decoded, data);

    Ok(())
}

API Reference

Encoding
encode<T: Serialize>(&value, &options) -> Result<String, ToonError>

Encode any serializable type to TOON format. Works with custom structs, enums, collections, and serde_json::Value.

use toon_format::{encode, EncodeOptions, Delimiter, Indent};
use serde_json::json;

let data = json!({"items": ["a", "b", "c"]});

// Default encoding
let toon = encode(&data, &EncodeOptions::default())?;
// items[3]: a,b,c

// Custom delimiter
let opts = EncodeOptions::new()
    .with_delimiter(Delimiter::Pipe);
let toon = encode(&data, &opts)?;
// items[3|]: a|b|c

// Custom indentation
let opts = EncodeOptions::new()
    .with_indent(Indent::Spaces(4));
let toon = encode(&data, &opts)?;
EncodeOptions
MethodDescriptionDefault
with_delimiter(d)Set delimiter: Comma, Tab, or PipeComma
with_indent(i)Set indentation (spaces only)Spaces(2)
with_spaces(n)Shorthand for Indent::Spaces(n)2
json_stream Feature

The optional json_stream feature adds conveniences for encoding JSON from a Read source to a Write target. Spec v4.4 selects the encoded form from a value's whole shape (tabular and keyed tabular headers depend on every element of their subtree), so the input is parsed in full before encoding; these functions are I/O conveniences, not bounded-memory streaming.

cargo add toon-format --features json_stream
use std::io::Cursor;
use toon_format::{encode_json_stream_default};

let input = Cursor::new(br#"{"users":[{"id":1,"name":"Alice"},{"id":2,"name":"Bob"}]}"#);
let mut output = Vec::new();
encode_json_stream_default(input, &mut output)?;
let toon = String::from_utf8(output)?;
assert!(toon.contains("users[2]{id,name}:"));
Decoding
decode<T: Deserialize>(&input, &options) -> Result<T, ToonError>

Decode TOON format into any deserializable type. Works with custom structs, enums, collections, and serde_json::Value.

With custom structs:

use serde::Deserialize;
use toon_format::{decode, DecodeOptions};

#[derive(Deserialize)]
struct Config {
    host: String,
    port: u16,
}

let toon = "host: localhost\nport: 8080";
let config: Config = decode(toon, &DecodeOptions::default())?;

With JSON values:

use serde_json::Value;
use toon_format::{decode, DecodeOptions};

let toon = "name: Alice\nage: 30";

// Default (strict) decode
let json: Value = decode(toon, &DecodeOptions::default())?;

// Non-strict mode
let opts = DecodeOptions::new().with_strict(false);
let json: Value = decode(toon, &opts)?;

Helper functions:

  • encode_default<T>(&value) - Encode with default options
  • decode_default<T>(&input) - Decode with default options
DecodeOptions
MethodDescriptionDefault
with_strict(b)Enable strict validationtrue
with_indent(i)Set spaces per indentation levelSpaces(2)

With with_strict(false), the decoder recovers from exactly five conditions (spec §14.4) and errors on everything else, as strict mode does:

  • A declared [N] is advisory: fewer or more items, rows, or entries than N still decode, but a row's width must match its fields.
  • Duplicate keys and repeated field names resolve last-write-wins.
  • Indentation may use tabs or non-multiples of the indent size: each tab is one level, spaces are floored.
  • Blank lines inside an array or keyed tabular object are ignored.
  • A block whose first line starts too deep takes that line's depth.

Spec v4.1 Highlights

Comment Lines (Decoder)

Lines whose first non-space character is # are comments, removed before any structural interpretation. Encoders never emit them.

# server inventory
servers[2]{host,port}:
  a.example.com,8080
  b.example.com,9090
Keyed Tabular Form

An object whose values are uniform non-empty objects collapses into a keyed header with one entry row per entry:

servers[2:]{host,port}:
  alpha: a.example.com,8080
  beta: b.example.com,9090
Nested Field Groups

A uniform nested-object column collapses into the header, its leaf cells laid out by a depth-first walk:

orders[2]{id,customer{name,country},total}:
  1,Ada,DK,99
  2,Bob,UK,149
Empty Arrays

Empty arrays encode as key: [] in field position and [] at the root; the legacy key[0]: and [0]: forms are still accepted by the decoder.


Interactive TUI

TOON includes a full-featured Terminal User Interface for interactive conversions!

# Launch interactive mode
toon --interactive
# or
toon -i
Features:
  • Real-time conversion as you type
  • Live statistics (tokens, bytes, savings)
  • Interactive settings - adjust all options on-the-fly
  • File browser with visual navigation
  • Side-by-side diff viewer
  • Conversion history tracking
  • File operations (open, save, new)
  • Clipboard integration (copy/paste)
  • REPL mode for command-line interaction
  • Round-trip testing
  • Theme support (Dark/Light)
  • Built-in help with keyboard shortcuts

Perfect for:

  • Learning TOON format interactively
  • Testing conversions in real-time
  • Experimenting with different settings
  • Visual before/after comparisons
  • Quick data transformations

See docs/TUI.md for complete documentation and keyboard shortcuts!


CLI Usage

Basic Commands
# Auto-detect from extension
toon data.json        # Encode
toon data.toon        # Decode

# Force mode
toon -e data.txt      # Force encode
toon -d output.txt    # Force decode

# Pipe from stdin
cat data.json | toon
echo '{"name": "Alice"}' | toon -e
Encode Options
# Custom delimiter
toon data.json --delimiter pipe
toon data.json --delimiter tab

# Custom indentation
toon data.json --indent 4

# Show statistics
toon data.json --stats
Decode Options
# Pretty-print JSON
toon data.toon --json-indent 2

# Relaxed validation
toon data.toon --no-strict
Full Example
$ echo '{"users":[{"id":1,"name":"Alice"},{"id":2,"name":"Bob"}]}' | toon --stats

users[2]{id,name}:
  1,Alice
  2,Bob

Stats:

+--------------+------+------+---------+
| Metric       | JSON | TOON | Savings |
+======================================+
| Tokens       | 20   | 19   | 5.00%   |
|--------------+------+------+---------|
| Size (bytes) | 58   | 36   | 37.93%  |
+--------------+------+------+---------+

Testing

The library includes a comprehensive test suite covering core functionality, edge cases, spec compliance, and real-world scenarios.

# Run all tests
cargo test

# Run specific test suites
cargo test --test spec_fixtures
cargo test --lib

# With output
cargo test -- --nocapture

Error Handling

All operations return Result<T, ToonError> with descriptive error messages:

use serde_json::Value;
use toon_format::{decode_strict, ToonError};

match decode_strict::<Value>("items[3]: a,b") {
    Ok(value) => println!("Success: {:?}", value),
    Err(ToonError::ParseError { line, message, .. }) => {
        eprintln!("Parse error on line {}: {}", line, message);
    }
    Err(e) => eprintln!("Error: {}", e),
}
Error Types
  • ParseError - Syntax, structural, and strict-mode errors with line info
  • TypeMismatch - Unexpected value type
  • InvalidStructure - Malformed TOON structure
  • SerializationError / DeserializationError - Conversion failures

Examples

Run with cargo run --example examples to see all examples:

  • structs.rs - Custom struct serialization
  • tabular.rs - Tabular array formatting
  • arrays.rs - Various array formats
  • arrays_of_arrays.rs - Nested arrays
  • objects.rs - Object encoding
  • mixed_arrays.rs - Mixed-type arrays
  • delimiters.rs - Custom delimiters
  • round_trip.rs - Encode/decode round-trips
  • decode_strict.rs - Strict validation
  • empty_and_root.rs - Edge cases

Resources


Contributing

Contributions are welcome! Please see CONTRIBUTING.md for guidelines.

Development
# Clone the repository
git clone https://github.com/your-org/toon-rust.git
cd toon-rust

# Run tests
cargo test --all

# Run lints
cargo clippy -- -D warnings

# Format code
cargo fmt

# Build docs
cargo doc --open

License

MIT License © 2025-PRESENT Johann Schopplich and Shreyas K S

Runs on
GPU support unknown
What shows it
  • no dependency or feature matches a backend row
Native code
None found
  • No native code found
Python bindings
No Python binding crate found
License
MIT

Compare with similar projects

Order: strongest tier first, then most downloads, then name, with unmeasured values last. A library counts downloads over 30 days. An app counts binary downloads per release. An app with none counts its crate downloads over 30 days. ML Rust runs this catalogue, so its closest project always gets a row.

toon-rust beside the projects that share a topic with it
ProjectDownloadsDependentsStarsLatest releaseRuns on (GPU)Native codeLicense
toon-rust This page Featured

Token-Oriented Object Notation (TOON) - a token-efficient JSON alternative for LLM prompts

160,383 downloads over 30 days 67 190 0.7.0 GPU support unknown No native code found MIT
pdf_oxide Featured

The fastest Rust PDF library — 0.8ms mean, 5× faster than the industry leaders, 100% pass rate on 3,830 real-world PDFs. Text extraction, Markdown/HTML conversion, PDF creation and editing.

Python bindings

316,729 downloads over 30 days 30 1,180 0.3.78 GPU support unknown Binds native code: aws-lc-rs (feature fips), lcms2-sys (feature icc-lcms2), ort-sys (feature gpu) Apache-2.0 OR MIT
oxidizePdf App Listed

Pure Rust PDF library for AI/RAG: structure-aware chunking, no ML, no C deps.

62,285 downloads over 30 days Not applicable 194 5.5.7 GPU support unknown No native code found MIT
toon-rs Listed Dormant

Token-Oriented Object Notation – a token-efficient JSON alternative for LLM prompts

8,018 downloads over 30 days 5 22 0.1.2 GPU support unknown No native code found MIT
serde_toon Listed

A Serde-compatible TOON (Token-Oriented Object Notation) serialization library

2,384 downloads over 30 days 4 13 0.3.0 GPU support unknown No native code found Apache-2.0 OR MIT
blazr App Listed

Inference server for LLMs, speech and embeddings: OpenAI-compatible routes with streaming, plus speech synthesis (TTS) and transcription (ASR). Serves Llama, Mistral, Qwen, Mamba2, MLA+MoE and hybrid models from SafeTensors, AWQ, GPTQ and GGUF.

8 binary downloads per release Not applicable 7 0.7.1 CUDA, WebGPU Binds native code: ring (feature distributed) Apache-2.0
chunkr App Listed

Vision infrastructure to turn complex documents into LLM-ready data

0 binary downloads per release Not applicable 4,157 Not measured Not measured AGPL-3.0
Why FeaturedIt passes every Featured gate.

What it meets

  • It has 46 active dependents and 46 new dependents in 365 days. Featured needs 11 active dependents or 9 new dependents in 365 days.
  • Active dependents are at 100% of their peak. Featured needs at least 50%.
  • Docs are present. The release commit or a manifest ties the crate to the repository.
  • No vulnerability advisory stays unpatched past the grace window. At least one version is neither a prerelease nor 0.0.x.
  • The last activity is on 12 Oct 2026, 28 days ago. The rules expect an update within 560 days. Dormancy rule

Exact rules: Featured library. The check on applied thresholds version 9.

Every rule outcome, as the check records it
  • expected-interval: version 0.7.0 base 140, doubled for 160383 downloads per month, doubled for 46 active users: E = 560 days
  • dormancy: last activity 2026-10-12, 28 days ago, E = 560: active
  • featured: featured: active_users 46, new_adopters 46, former_glory 1

Measurements and sources

Each signal row shows the raw value, its source and the fetch date. The Sources list gathers every distinct source on this page. Movement needs more history.

Sources6 sources
Adoption46 active dependents, 46 new dependents in 365 days1 not measured
Adoption measurements
SignalValueSourceFetchedCounts
Active dependents46crates.io database dumpYes
New dependents (365 days)46crates.io database dumpYes
Peak active dependents46crates.io database dumpYes
Active dependents as a share of the peak1crates.io database dumpYes
Binary downloads per releaseNot measuredYes
MaintenanceLatest human commit: 28 days ago3 not measured
Maintenance measurements
SignalValueSourceFetchedCounts
Latest human commit2026-10-12GitHub repositoryYes
Latest release2026-10-12crates.io database dumpYes
First release2025-11-01crates.io database dumpYes
Latest version0.7.0crates.io database dumpYes
Days the oldest outside issue waits for a reply0GitHub repositoryYes
Maintainer replies over 365 days32GitHub repositoryYes
Repository archivedfalseGitHub repositoryYes
Repository gonefalseGitHub repositoryYes
Release commit or manifest in the repotruecrates.io packageYes
Published docstruecrates.io database dumpYes
Latest release fails cargo checkNot measuredYes
Build check dateNot measuredYes
Build check toolchainNot measuredYes
SecurityUnpatched vulnerabilities: none
Security measurements
SignalValueSourceFetchedCounts
Unpatched vulnerabilities past the grace windownoneRustSec advisory databaseYes
RustSec unmaintained advisorynoneRustSec advisory databaseYes
Deprecation noticenonecrates.io database dumpYes
Deprecated requirementnonecrates.io database dumpYes
Distribution25 releases, 160,383 downloads over 30 days5 not measured
Distribution measurements
SignalValueSourceFetchedCounts
Releases25crates.io database dumpYes
Downloads over 30 days160383crates.io database dumpYes
Binary downloads over the last 3 releasesNot measuredYes
Homebrew installs on request over 365 daysNot measuredYes
Repology repository familiesNot measuredYes
Docker pull growth over 90 daysNot measuredYes
Docker pulls at the growth baselineNot measuredYes
Every version a prereleasefalsecrates.io database dumpYes
Every version 0.0.xfalsecrates.io database dumpYes
Every version yankedfalsecrates.io database dumpYes
Crate deleted from crates.iofalsecrates.io database dumpYes
Repository190 stars, 28 forks, 10 contributors, 80 commits. Stars alone never qualify a project.
Repository measurements
SignalValueSourceFetchedCounts
GitHub stars190GitHub repositoryYes — one part of the repository route
GitHub forks28GitHub repositoryYes — one part of the repository route
Contributors with a GitHub account10GitHub contributorsYes — one part of the repository route
Commits on the default branch80GitHub repositoryNo
Repository's main crate left out of the entrynonecrates.io database dumpYes
Facts that never count
Facts that never count measurements
SignalValueSourceFetchedCounts
LicenseMITcrates.io database dumpNo
Runs on, from listed crates and their direct dependenciesGPU support unknowncrates.io database dumpNo
What shows each backendno dependency or feature matches a backend rowcrates.io database dumpNo
Native code, from listed crates and their dependenciesNo native code foundcrates.io database dumpNo
Python bindings, from direct dependencies of listed cratesNo Python binding crate foundcrates.io database dumpNo
Crates that depend on a listed crate directly67crates.io database dumpNo

Corrections and review history

Report a correction

No correction applies to this entry.

Judgments

A judgment enters only through an approved issue and a merged pull request.

No judgment applies to this entry.