| Crates.io | serde_toon2 |
| lib.rs | serde_toon2 |
| version | 0.1.0 |
| created_at | 2025-11-13 23:05:53.781118+00 |
| updated_at | 2025-11-13 23:05:53.781118+00 |
| description | Serde-compatible serializer and deserializer for TOON (Token-Oriented Object Notation) |
| homepage | https://github.com/danielkov/toon-rust |
| repository | https://github.com/danielkov/toon-rust |
| max_upload_size | |
| id | 1932002 |
| size | 250,052 |
Serde-compatible serializer/deserializer for TOON (Token-Oriented Object Notation), a line-oriented, indentation-based format that encodes the JSON data model.
None of the other TOON crates (at the time of writing this) implement the TOON spec in its entirety. I needed a crate that actually worked as expected, so I've built one.
Fixtures in tests/fixtures will be kept up to date with official tests.
[dependencies]
serde_toon2 = "0.1.0"
serde = { version = "1.0", features = ["derive"] }
TOON encodes JSON structures using indentation instead of braces:
user:
id: 123
name: Ada
items[2]: a,b
Equivalent JSON:
{ "user": { "id": 123, "name": "Ada" }, "items": ["a", "b"] }
Characteristics:
[3] or [3 name,age]use serde::Serialize;
use serde_toon2::{to_string, to_string_with_options, EncoderOptions, Delimiter};
#[derive(Serialize)]
struct User {
id: u64,
name: String,
}
let user = User { id: 42, name: "Ada".to_string() };
// Default options
let toon = to_string(&user)?;
// Output: "id: 42\nname: Ada"
// Custom options
let opts = EncoderOptions {
indent: 4,
delimiter: Delimiter::Pipe,
..Default::default()
};
let toon = to_string_with_options(&user, &opts)?;
pub struct EncoderOptions {
pub indent: usize, // Spaces per indent level (default: 2)
pub delimiter: Delimiter, // Array delimiter (default: Comma)
pub key_folding: KeyFolding, // Path compression (default: Off)
pub flatten_depth: usize, // Max depth to inline (default: MAX)
}
pub enum Delimiter {
Comma, // items[3]: a,b,c
Tab, // items[3]\t: a\tb\tc
Pipe, // items[3]|: a|b|c
}
use serde::Deserialize;
use serde_toon2::{from_str, from_str_with_options, DecoderOptions};
#[derive(Deserialize)]
struct User {
id: u64,
name: String,
}
let toon = "id: 42\nname: Ada";
let user: User = from_str(toon)?;
// Strict mode validation
let opts = DecoderOptions {
strict: true,
..Default::default()
};
let user: User = from_str_with_options(toon, &opts)?;
pub struct DecoderOptions {
pub indent: usize, // Expected indent size (default: 2)
pub strict: bool, // Enable strict validation (default: false)
pub expand_paths: PathExpansion, // Path notation handling (default: Off)
}
to_string<T: Serialize>(value: &T) -> Result<String>to_string_with_options<T: Serialize>(value: &T, options: &EncoderOptions) -> Result<String>to_vec<T: Serialize>(value: &T) -> Result<Vec<u8>>to_vec_with_options<T: Serialize>(value: &T, options: &EncoderOptions) -> Result<Vec<u8>>to_writer<W: Write, T: Serialize>(writer: W, value: &T) -> Result<()>to_writer_with_options<W: Write, T: Serialize>(writer: W, value: &T, options: &EncoderOptions) -> Result<()>from_str<'a, T: Deserialize<'a>>(s: &'a str) -> Result<T>from_str_with_options<'a, T: Deserialize<'a>>(s: &'a str, options: &DecoderOptions) -> Result<T>from_slice<'a, T: Deserialize<'a>>(v: &'a [u8]) -> Result<T>from_slice_with_options<'a, T: Deserialize<'a>>(v: &'a [u8], options: &DecoderOptions) -> Result<T>from_reader<R: Read, T: DeserializeOwned>(reader: R) -> Result<T>from_reader_with_options<R: Read, T: DeserializeOwned>(reader: R, options: &DecoderOptions) -> Result<T>Strongly-typed errors with location information:
pub enum ErrorKind {
InvalidSyntax,
InvalidEscape,
UnterminatedString,
MissingColon,
IndentationError,
BlankLineInArray,
CountMismatch, // Array length mismatch
WidthMismatch, // Field count mismatch
DelimiterMismatch,
InvalidHeader,
// ...
}
Errors include line/column location when available:
Invalid syntax at line 5, column 12
Generic value type for dynamic content:
pub enum Value {
Null,
Bool(bool),
Number(Number),
String(String),
Array(Vec<Value>),
Object(Map<String, Value>),
}
pub type Map<K, V> = indexmap::IndexMap<K, V>; // Preserves insertion order
name: Ada
age: 42
active: true
user:
name: Ada
profile:
bio: Programmer
location: London
tags[3]: rust,serde,parser
tags[3]:
rust
serde
parser
users[2]:
name: Ada
age: 42
---
name: Bob
age: 35
users[2 name,age]:
Ada,42
Bob,35
scores[3] : 95 87 92
paths[2]|: /usr/bin|/usr/local/bin
serde 1.0 - Serialization frameworkindexmap 2.0 - Order-preserving mapsMIT