A high-performance serialisation library for the TOON format — a compact, human-readable alternative to JSON. Built on a fast C core, exposing idiomatic APIs for C, C++, Go, Julia, MATLAB, Python, Rust, and Zig.
The same weather forecast in both formats (example from the TOON repository): about 117 tokens as JSON against about 66 as TOON, roughly 44% fewer (GPT-5 tokenizer; other tokenizers differ, but the relative gap holds).
{
"location": {
"city": "Berlin",
"country": "DE",
"units": "metric"
},
"alerts": [
"frost",
"wind"
],
"forecast": [
{
"day": "Mon",
"temp": {
"min": -2,
"max": 4
},
"condition": "snow",
"rainChance": 80
},
{
"day": "Tue",
"temp": {
"min": 1,
"max": 7
},
"condition": "cloudy",
"rainChance": 20
},
{
"day": "Wed",
"temp": {
"min": 3,
"max": 11
},
"condition": "sunny",
"rainChance": 5
}
]
}
location:
city: Berlin
country: DE
units: metric
alerts[2]: frost,wind
forecast[3]{day,temp{min,max},condition,rainChance}:
Mon,-2,4,snow,80
Tue,1,7,cloudy,20
Wed,3,11,sunny,5
alerts[2]: frost,wind — inline form: a primitive array on a single line, with its length declared.forecast[3]{day,…}: — tabular form: the field list is written once in the header, then one row per element.temp{min,max} — a nested field group: the uniform nested temp objects fold into the header, so rows stay flat.
[N] (row count) and {fields} (columns) also act as guardrails: truncated or malformed
model output is easy to detect. TOON is at its best on arrays of uniform objects; for deeply nested or
non-uniform data, compact JSON can be smaller. See the
TOON repository
for the full format overview, specification and LLM benchmarks.
Command-line tool for converting between JSON and TOON formats. Covers all options and flags including --delimiter, --length-marker, --stats, stdin piping, and forced encode/decode modes. Auto-detects conversion direction from file extension.
Core library interface. Covers document parsing with ctoon_read, serialisation with ctoon_write, JSON export via ctoon_doc_to_json, and full value-traversal API including ctoon_obj_get, ctoon_arr_get, and typed getters. Zero dependencies beyond the C standard library.
Header-only RAII wrappers around the C core. Covers ctoon::document, ctoon::value, ctoon::make_document, EncodeOptions, DecodeOptions, and read/write flag enums. All objects manage lifetime automatically — no manual free calls needed.
CGo bindings that wrap the C core. Covers Loads, Dumps, LoadsJSON, DumpsJSON, file I/O helpers (EncodeToFile, DecodeFromFile), and encode/decode option structs. Requires CGo-enabled build environment.
Dependency-free ccall wrapper around the C core, built by compiling ctoon.c directly (no separate C library install needed). Documents CToon.parse, which reads JSON via ctoon_read_json into native Dict/Vector/String/number/Bool/nothing values.
MEX-based binding for the CToon C library. Documents ctoon.encode, ctoon.decode, ctoon.read, and ctoon.write (plus Python-style aliases ctoon.dumps/ctoon.loads). Works with any MATLAB R2014b or newer — no toolboxes required. Build with ctoon_build or via CMake.
nanobind-based extension module. Documents loads, dumps, load, dump, JSON interop functions (loads_json, dumps_json), and the ReadFlag / WriteFlag / Delimiter enums. Ships pre-built wheels for Linux, macOS, and Windows.
Safe wrapper around the C core with a dependency-free Value enum (no serde_json required). Covers loads, dumps, loads_json, dumps_json, and Error. Compiles ctoon.c directly via a build.rs — no separate C library install needed.
Dependency-free wrapper around the C core with a tagged-union Value type. Covers loads, dumps, loadsJson, dumpsJson, and lastError. Compiles ctoon.c directly via build.zig — no CMake step needed to build or test it on its own.
pip install ctoon
ctoon binary alongside the Python extension. After install, the ctoon command is available directly in your shell — no compiler or CMake needed.
git clone https://github.com/MohammadRaziei/ctoon.git
cd ctoon
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j$(nproc)
# Install to system (adds `ctoon` to PATH)
sudo cmake --install build
# CMakeLists.txt
include(FetchContent)
FetchContent_Declare(
ctoon
GIT_REPOSITORY https://github.com/MohammadRaziei/ctoon.git
GIT_TAG main
)
FetchContent_MakeAvailable(ctoon)
# Link the C target
target_link_libraries(my_app PRIVATE ctoon::ctoon)
ctoon::ctoon and include ctoon.h.
# CMakeLists.txt
include(FetchContent)
FetchContent_Declare(
ctoon
GIT_REPOSITORY https://github.com/MohammadRaziei/ctoon.git
GIT_TAG main
)
FetchContent_MakeAvailable(ctoon)
# Link the C++ target
target_link_libraries(my_app PRIVATE ctoon::ctoonpp)
ctoon::ctoonpp and include ctoon.hpp. The C++ wrapper is header-only on top of the C core — all RAII lifetime management is included automatically.
go get github.com/mohammadraziei/ctoon
CGO_ENABLED=1). The module bundles the C core source — no separate C library install is needed. A C compiler (gcc / clang) must be available on the build host.
import Pkg
Pkg.add(url="https://github.com/mohammadraziei/ctoon.git", subdir="src/bindings/julia")
subdir points Pkg.add at the binding inside this monorepo, the standard way to install one package out of several living in one git repo. Building runs automatically as part of Pkg.add — no separate C library install needed, deps/build.jl compiles ctoon.c directly.
cd src/bindings/matlab
ctoon_install
mex -setup C).
ctoon_install compiles the MEX gateway and permanently adds the binding to your MATLAB path.
For MATLAB R2022b+ you can also use buildtool mex.
pip install ctoon
pip install git+https://github.com/MohammadRaziei/ctoon
[dependencies]
ctoon = { git = "https://github.com/mohammadraziei/ctoon.git" }
build.rs compiles ctoon.c directly into the crate, so no separate C library install is needed. A C compiler must be available on the build host.
zig fetch --save git+https://github.com/mohammadraziei/ctoon.git
build.zig: exe.root_module.addImport("ctoon", ctoon_dep.module("ctoon")). No separate C library install needed — build.zig compiles ctoon.c directly.
# JSON → TOON (auto-detected from extension)
ctoon input.json
ctoon input.json -o output.toon
# TOON → JSON with pretty-printing
ctoon input.toon
ctoon input.toon -o output.json -i 4
# Read from stdin
cat data.json | ctoon -e -
# Encoder options
ctoon input.json --delimiter pipe # comma (default), tab, pipe
ctoon input.json --length-marker # emit items[#3]: …
ctoon input.json --stats # print byte-savings summary
# Force conversion direction
ctoon -e input.json # force encode JSON → TOON
ctoon -d input.toon # force decode TOON → JSON
#include "ctoon.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
const char *src = "name: Alice\nage: 30";
ctoon_doc *doc = ctoon_read(src, strlen(src), 0);
ctoon_val *root = ctoon_doc_get_root(doc);
/* Access fields */
ctoon_val *name = ctoon_obj_get(root, "name");
printf("%s\n", ctoon_get_str(name)); /* Alice */
/* Serialise back to TOON */
size_t len;
char *toon = ctoon_write(doc, &len);
free(toon);
/* Export as JSON (on by default; define CTOON_DISABLE_JSON to turn off) */
char *json = ctoon_doc_to_json(doc, 2,
CTOON_WRITE_NOFLAG, NULL, &len, NULL);
printf("%s\n", json);
free(json);
ctoon_doc_free(doc);
return 0;
}
#include "ctoon.hpp"
#include <iostream>
int main() {
// Parse a TOON document
auto doc = ctoon::document::parse("name: Alice\nage: 30");
auto root = doc.root();
std::cout << root["name"].get_str().str() << "\n"; // Alice
std::cout << root["age"].get_uint() << "\n"; // 30
// Serialise to TOON and JSON
std::cout << doc.to_string().c_str() << "\n";
std::cout << doc.to_json(2).c_str() << "\n";
// Build a document programmatically
auto mdoc = ctoon::make_document();
auto obj = mdoc.make_obj();
mdoc.set_root(obj);
obj.obj_put(mdoc.make_str("city"), mdoc.make_str("Tehran"));
obj.obj_put(mdoc.make_str("pop"), mdoc.make_uint(9000000));
std::cout << mdoc.to_json(0).c_str() << "\n";
// Parse from JSON
auto jdoc = ctoon::document::from_json(R"({"x":1,"y":2})");
std::cout << jdoc.root()["x"].get_uint() << "\n"; // 1
}
package main
import (
"fmt"
ctoon "github.com/mohammadraziei/ctoon"
)
func main() {
data := map[string]interface{}{
"name": "Alice",
"age": int64(30),
}
// Encode → TOON
toon, _ := ctoon.Dumps(data)
fmt.Println(toon)
// Decode ← TOON
val, _ := ctoon.Loads(toon)
fmt.Println(val)
// File I/O
ctoon.EncodeToFile(data, "out.toon", ctoon.DefaultEncodeOptions())
val, _ = ctoon.DecodeFromFile("out.toon", ctoon.DefaultDecodeOptions())
// JSON interop
json, _ := ctoon.DumpsJSON(data, 2)
fmt.Println(json)
ctoon.DumpJSON(data, "out.json")
}
using CToon
# Parse JSON → native Julia data
data = CToon.parse("""{"name": "Alice", "age": 30}""")
println(data["name"]) # Alice
println(data["age"]) # 30
# Objects decode as order-preserving OrderedDict{String,Any},
# arrays as Vector{Any}
nested = CToon.parse("""{"items": [1, 2, 3]}""")
println(nested["items"]) # Any[1, 2, 3]
% Encode a MATLAB struct → TOON string
s = ctoon.encode(struct('name', 'Alice', 'age', uint64(30), 'active', true));
% name: Alice
% age: 30
% active: true
% Decode TOON string → MATLAB struct
v = ctoon.decode(s);
v.name % 'Alice'
v.age % uint64(30)
v.active % true
% File I/O
ctoon.write(v, 'data.toon');
v = ctoon.read('data.toon');
% Python-style aliases
s = ctoon.dumps(v); % same as ctoon.encode
v = ctoon.loads(s); % same as ctoon.decode
import ctoon
# Encode Python dict → TOON string
toon = ctoon.dumps({"name": "Alice", "age": 30})
# name: Alice
# age: 30
# Decode TOON string → Python dict
data = ctoon.loads(toon)
# File I/O — path strings or file-like objects
ctoon.dump(data, "out.toon")
data = ctoon.load("out.toon")
# JSON interop
json_str = ctoon.dumps_json(data, indent=2)
data = ctoon.loads_json(json_str)
ctoon.dump_json(data, "out.json")
# Advanced encode flags
from ctoon import WriteFlag, Delimiter
toon = ctoon.dumps(data,
indent=4,
delimiter=Delimiter.PIPE,
flags=WriteFlag.LENGTH_MARKER | WriteFlag.NEWLINE_AT_END)
fn main() -> ctoon::Result<()> {
// Decode ← TOON
let val = ctoon::loads("name: Alice\nage: 30")?;
println!("{}", val["name"].as_str().unwrap()); // Alice
// Encode → TOON
let toon = ctoon::dumps(&val)?;
println!("{toon}");
// JSON interop
let json = ctoon::dumps_json(&val, 2)?;
let back = ctoon::loads_json(&json)?;
println!("{}", back["age"].as_u64().unwrap()); // 30
Ok(())
}
const std = @import("std");
const ctoon = @import("ctoon");
pub fn main() !void {
const gpa = std.heap.page_allocator;
// Decode ← TOON
var val = try ctoon.loads(gpa, "name: Alice\nage: 30");
defer val.deinit(gpa);
std.debug.print("{s}\n", .{val.get("name").?.asStr().?}); // Alice
// Encode → TOON
const toon = try ctoon.dumps(gpa, val);
defer gpa.free(toon);
// JSON interop
const json = try ctoon.dumpsJson(gpa, val, 2);
defer gpa.free(json);
var back = try ctoon.loadsJson(gpa, json);
defer back.deinit(gpa);
std.debug.print("{}\n", .{back.get("age").?.asU64().?}); // 30
}