๐ฆ RToon
Rust implementation of TOON (Token-Oriented Object Notation)
A compact, token-efficient format for structured data in LLM applications
Token-Oriented Object Notation is a compact, human-readable format designed for passing structured data to Large Language Models with significantly reduced token usage. This is a Rust implementation of the TOON specification.
[!TIP] Think of TOON as a translation layer: use JSON programmatically, convert to TOON for LLM input.
Table of Contents
- Why TOON?
- Key Features
- Installation
- Quick Start
- Examples
- API Reference
- Format Overview
- Specification
- Running Examples
- Contributing
- License
- See Also
Why TOON?
AI is becoming cheaper and more accessible, but larger context windows allow for larger data inputs as well. LLM tokens still cost money โ and standard JSON is verbose and token-expensive.
JSON vs TOON Comparison
JSON (verbose, token-heavy):
TOON (compact, token-efficient):
users[2]{id,name,role}:
1,Alice,admin
2,Bob,user
TOON conveys the same information with 30โ60% fewer tokens! ๐
Key Features
- ๐ธ Token-efficient: typically 30โ60% fewer tokens than JSON
- ๐คฟ LLM-friendly guardrails: explicit lengths and fields enable validation
- ๐ฑ Minimal syntax: removes redundant punctuation (braces, brackets, most quotes)
- ๐ Indentation-based structure: like YAML, uses whitespace instead of braces
- ๐งบ Tabular arrays: declare keys once, stream data as rows
- ๐ Round-trip support: encode and decode with full fidelity
- ๐ก๏ธ Type-safe: integrates seamlessly with
serde_json::Value - โ๏ธ Customizable: delimiter (comma/tab/pipe), length markers, and indentation
Installation
Add to your Cargo.toml:
[]
= "0.1.3"
= "1.0"
Quick Start
use encode_default;
use json;
Output:
user:
active: true
id: 123
name: Ada
tags[2]: reading,gaming
Examples
๐ Note: All examples in this section are taken from the
examples/directory. Runcargo run --example examplesto see them in action.
Objects
Simple objects encode as key-value pairs:
use encode_default;
use json;
let data = json!;
println!;
Output:
active: true
id: 123
name: Ada
Nested objects use indentation:
let nested = json!;
println!;
Output:
user:
id: 123
name: Ada
Primitive Arrays
Primitive arrays are inline with count and delimiter-separated values:
use encode_default;
use json;
let data = json!;
println!;
Output:
tags[3]: admin,ops,dev
Arrays of Objects (Tabular)
When arrays contain uniform objects with the same keys and primitive-only values, they're encoded in tabular format for maximum token efficiency:
use encode_default;
use json;
let data = json!;
println!;
Output:
items[2]{sku,qty,price}:
A1,2,9.99
B2,1,14.5
Tabular arrays can be nested:
let nested = json!;
println!;
Output:
items[1]:
status: active
users[2]{id,name}:
1,Ada
2,Bob
Arrays of Arrays
When arrays contain other primitive arrays, they're expanded as list items:
use encode_default;
use json;
let data = json!;
println!;
Output:
pairs[2]:
- [2]: 1,2
- [2]: 3,4
Mixed Arrays
Non-uniform arrays (containing primitives, objects, or nested arrays) use the expanded list format:
use encode_default;
use json;
let mixed = json!;
println!;
Output:
items[3]:
- 1
- a: 1
- text
Objects in list format place the first field on the hyphen line:
let list_objects = json!;
println!;
Output:
items[2]:
- id: 1
name: First
- id: 2
name: Second
extra: true
Custom Delimiters
Use tab or pipe delimiters to avoid quoting and save more tokens:
use ;
use json;
let data = json!;
// Tab delimiter (\t)
let tab = encode.unwrap;
println!;
// Pipe delimiter (|)
let pipe = encode.unwrap;
println!;
Length Markers
Prefix array lengths with a marker character for clarity:
use ;
use json;
let data = json!;
let opts = new.with_length_marker;
println!;
Output:
items[#2]{sku,qty,price}:
A1,2,9.99
B2,1,14.5
tags[#3]: reading,gaming,coding
Empty Containers & Root Forms
Empty arrays and objects are supported:
use encode_default;
use json;
// Empty array
let empty_items = json!;
println!;
// Root array
let root_array = json!;
println!;
Output:
items[0]:
[2]: x,y
Empty objects at root encode to empty output.
Round-Trip Encoding
TOON supports full round-trip encoding and decoding:
use ;
use json;
let original = json!;
let encoded = encode_default.unwrap;
let decoded = decode_default.unwrap;
assert_eq!;
println!;
Strict Mode Decoding
Strict mode enforces array counts, indentation, and delimiter consistency:
use ;
// Malformed: header says 2 rows, but only 1 provided
let malformed = "items[2]{id,name}:\n 1,Ada";
let opts = new.with_strict;
match decode
Strict mode (default) checks:
- Array counts must match declared lengths
- Indentation must be exact multiples of indent size
- Tabs cannot be used for indentation
- Invalid escape sequences cause errors
- Missing colons after keys cause errors
- Blank lines inside arrays/tabular rows cause errors
API Reference
Encoding Functions
Decoding Functions
EncodeOptions
Example:
use ;
let opts = new
.with_delimiter
.with_length_marker
.with_spaces;
// Or
let opts = new
.with_delimiter
.with_length_marker
.with_tabs;
// Or
use Indent;
let opts = new
.with_indent;
DecodeOptions
Example:
use ;
let opts = new
.with_strict
.with_delimiter;
Delimiter
Error Handling
All functions return ToonResult<T>, which is Result<T, ToonError>. The error type provides detailed information about parsing or encoding failures:
use ;
match decode_default
Format Overview
- Objects:
key: valuewith 2-space indentation for nesting - Primitive arrays: inline with count, e.g.,
tags[3]: a,b,c - Arrays of objects: tabular header, e.g.,
items[2]{id,name}:\n ... - Mixed arrays: list format with
-prefix - Quoting: only when necessary (special chars, ambiguity, keywords like
true,null) - Root forms: objects (default), arrays, or primitives
For complete format specification, see SPEC.md.
Specification
This implementation follows the TOON Specification v1.2. The specification defines:
- Data model and normalization rules
- Encoding and decoding semantics
- Header syntax and delimiter scoping
- Quoting rules and escaping
- Strict mode validation requirements
Refer to SPEC.md for complete details.
Running Examples
Run the consolidated examples:
This executes examples/main.rs, which invokes all parts under examples/parts/:
arrays.rsโ Primitive array encodingarrays_of_arrays.rsโ Nested primitive arraysobjects.rsโ Simple and nested objectstabular.rsโ Tabular array encodingdelimiters.rsโ Custom delimiter usagemixed_arrays.rsโ Mixed/non-uniform arrayslength_marker.rsโ Length marker examplesempty_and_root.rsโ Edge cases and root formsround_trip.rsโ Encoding and decoding verificationdecode_strict.rsโ Strict mode validation
Contributing
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
License
MIT ยฉ 2025
See Also
- Original JavaScript/TypeScript implementation: @byjohann/toon
Built with โค๏ธ in Rust