Skip to content

MohammadRaziei/ctoon

Repository files navigation

CToon Long Logo

The fastest implementation of the TOON format — a compact, human-readable serialisation format designed to minimise LLM token usage. Achieves 30-60% token reduction versus JSON while remaining fully readable and structured.

CToon is built on a high-performance C core and exposes the same logic through idiomatic bindings for C++, Python, Go, and MATLAB. The name reflects its foundation: C + TOON.

Format Overview

# JSON  (352 bytes)                  # TOON  (165 bytes, -53 %)
{                                    order:
  "order": {                           id: ORD-12345
    "id": "ORD-12345",                 status: completed
    "items": [                         customer:
      {"product":"Book","qty":2},        name: John Doe
      {"product":"Pen","qty":5}          email: john@example.com
    ]                                  items[2]{product,qty}:
  }                                      Book,2
}                                        Pen,5

Quick Start

CLI

cmake -B build && cmake --build build
./build/ctoon data.json           # JSON  -> TOON
./build/ctoon data.toon           # TOON  -> JSON
cat data.json | ./build/ctoon     # stdin -> TOON

C

#include "ctoon.h"

ctoon_doc *doc = ctoon_read("name: Alice\nage: 30", 20, 0);
ctoon_val *root = ctoon_doc_get_root(doc);

ctoon_val *name = ctoon_obj_get(root, "name");
printf("%s\n", ctoon_get_str(name));     /* Alice */

size_t len;
char *toon = ctoon_write(doc, &len);     /* caller must free() */
free(toon);
ctoon_doc_free(doc);

/* JSON output (requires CTOON_ENABLE_JSON=1, on by default) */
char *json = ctoon_doc_to_json(doc, 2, CTOON_WRITE_NOFLAG, NULL, &len, NULL);
free(json);

C++

#include "ctoon.hpp"

/* Parse TOON */
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 */
std::cout << doc.write().c_str()    << "\n";  // TOON
std::cout << doc.to_json(2).c_str() << "\n";  // JSON

/* Build a mutable document */
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(9'000'000));
std::cout << mdoc.to_json(0).c_str() << "\n";  // {"city":"Tehran","pop":9000000}

Python

import ctoon

# encode / decode
toon = ctoon.dumps({"name": "Alice", "age": 30})
data = ctoon.loads(toon)

# file I/O
ctoon.dump(data, "out.toon")
data = ctoon.load("out.toon")

# JSON
json_str = ctoon.dumps_json(data, indent=2)
data     = ctoon.loads_json(json_str)

Go

import ctoon "github.com/mohammadraziei/ctoon"

// encode / decode
toon, _ := ctoon.Dumps(map[string]interface{}{"name": "Alice", "age": int64(30)})
val,  _ := ctoon.Loads(toon)

// file I/O
ctoon.EncodeToFile(data, "out.toon", ctoon.DefaultEncodeOptions())
val, _ = ctoon.DecodeFromFile("out.toon", ctoon.DefaultDecodeOptions())

MATLAB

% Install once (compiles MEX and adds to MATLAB path permanently)
cd src/bindings/matlab
ctoon_install

% Versin / info
ctoon.version
v = ctoon.version
[v, info] = ctoon.version

% Encode / decode
s = ctoon.encode(struct('name', 'Alice', 'age', uint64(30), 'active', true));
v = ctoon.decode(s);
v.name    % -> 'Alice'
v.age     % -> uint64(30)
v.active  % -> true

% Python-style aliases
s = ctoon.dumps(v);
v = ctoon.loads(s);

% File I/O  (filename)
ctoon.write(v, 'config.toon');
v = ctoon.read('config.toon');

% File I/O  (open fid)
fid = fopen('config.toon', 'w');
ctoon.dump(v, fid);
fclose(fid);

fid = fopen('config.toon', 'r');
v = ctoon.load(fid);
fclose(fid);

MATLAB type mapping:

MATLAB TOON
[] null
logical bool
double scalar real
int64 scalar sint
uint64 scalar uint
char str
cell array
struct object

Requires MATLAB R2014b+ and a C compiler configured for MEX (mex -setup C).


Build

cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j$(nproc) --target ctoon_test     # Run all tests
cmake --build build -j$(nproc) --target ctoon_coverage # Generate coverage reports

CMake options

Option Default Description
CTOON_BUILD_TESTS ON Build C and C++ tests
CTOON_BUILD_PYTHON OFF Build Python extension (nanobind)
CTOON_BUILD_MATLAB OFF Build MATLAB MEX binding
CTOON_BUILD_DOCS OFF Build documentation

JSON support is on by default (CTOON_ENABLE_JSON=1). No external JSON library required.

Python package

pip install ctoon

Go module

go get github.com/mohammadraziei/ctoon

Requires Go 1.21+. Uses CGo to call the C core.

MATLAB MEX

# Via CMake
cmake -B build -DCTOON_BUILD_MATLAB=ON -DMatlab_ROOT_DIR=/path/to/matlab
cmake --build build --target ctoon_build_mex

# Or directly from MATLAB
cd src/bindings/matlab
ctoon_install        % compile + add to path permanently

CLI Reference

# Encode  JSON -> TOON
ctoon input.json
ctoon input.json -o output.toon
ctoon input.json --delimiter pipe      # comma (default), tab, pipe
ctoon input.json --length-marker       # items[#3]: ...
ctoon input.json --stats               # show byte savings

# Decode  TOON -> JSON
ctoon input.toon
ctoon input.toon -o output.json
ctoon input.toon -i 4                  # 4-space JSON indent

# Force format (auto-detected from extension by default)
ctoon -e input.json    # force encode
ctoon -d input.toon    # force decode

# Stdin
cat data.json | ctoon -e -
cat data.toon | ctoon -d -

C API Reference

Parsing

/* from memory */
ctoon_doc *ctoon_read(const char *toon, size_t len, ctoon_read_flag flags);
ctoon_doc *ctoon_read_opts(char *toon, size_t len, ctoon_read_flag flags,
                            const ctoon_alc *alc, ctoon_read_err *err);
/* from file */
ctoon_doc *ctoon_read_file(const char *path, ctoon_read_flag flags,
                            const ctoon_alc *alc, ctoon_read_err *err);
/* from JSON */
ctoon_doc *ctoon_read_json(char *json, size_t len, ctoon_read_flag flags,
                            const ctoon_alc *alc, ctoon_read_err *err);
ctoon_doc *ctoon_read_json_file(const char *path, ctoon_read_flag flags,
                                 const ctoon_alc *alc, ctoon_read_err *err);

Writing

/* TOON output */
char *ctoon_write(const ctoon_doc *doc, size_t *len);
char *ctoon_write_opts(const ctoon_doc *doc, const ctoon_write_options *opts,
                        const ctoon_alc *alc, size_t *len, ctoon_write_err *err);
char *ctoon_mut_write(const ctoon_mut_doc *doc, size_t *len);

/* JSON output */
char *ctoon_doc_to_json(const ctoon_doc *doc, int indent,
                         ctoon_write_flag flags, const ctoon_alc *alc,
                         size_t *len, ctoon_write_err *err);

Access

/* document */
ctoon_val *ctoon_doc_get_root(const ctoon_doc *doc);
void       ctoon_doc_free(ctoon_doc *doc);

/* type checks */
bool ctoon_is_null(ctoon_val *v);   bool ctoon_is_bool(ctoon_val *v);
bool ctoon_is_true(ctoon_val *v);   bool ctoon_is_false(ctoon_val *v);
bool ctoon_is_uint(ctoon_val *v);   bool ctoon_is_sint(ctoon_val *v);
bool ctoon_is_real(ctoon_val *v);   bool ctoon_is_str(ctoon_val *v);
bool ctoon_is_arr(ctoon_val *v);    bool ctoon_is_obj(ctoon_val *v);

/* getters */
const char *ctoon_get_str(ctoon_val *v);
uint64_t    ctoon_get_uint(ctoon_val *v);
int64_t     ctoon_get_sint(ctoon_val *v);
double      ctoon_get_real(ctoon_val *v);
bool        ctoon_get_bool(ctoon_val *v);

/* array */
size_t     ctoon_arr_size(ctoon_val *arr);
ctoon_val *ctoon_arr_get(ctoon_val *arr, size_t idx);   /* O(1) */

/* object */
size_t     ctoon_obj_size(ctoon_val *obj);
ctoon_val *ctoon_obj_get(ctoon_val *obj, const char *key);

/* iteration */
ctoon_obj_iter ctoon_obj_iter_with(ctoon_val *obj);
ctoon_val     *ctoon_obj_iter_next(ctoon_obj_iter *iter);
ctoon_val     *ctoon_obj_iter_get_val(ctoon_val *key);

Mutable documents

ctoon_mut_doc *ctoon_mut_doc_new(const ctoon_alc *alc);
void           ctoon_mut_doc_free(ctoon_mut_doc *doc);
void           ctoon_mut_doc_set_root(ctoon_mut_doc *doc, ctoon_mut_val *root);

ctoon_mut_val *ctoon_mut_null(ctoon_mut_doc *doc);
ctoon_mut_val *ctoon_mut_bool(ctoon_mut_doc *doc, bool val);
ctoon_mut_val *ctoon_mut_uint(ctoon_mut_doc *doc, uint64_t val);
ctoon_mut_val *ctoon_mut_sint(ctoon_mut_doc *doc, int64_t val);
ctoon_mut_val *ctoon_mut_real(ctoon_mut_doc *doc, double val);
ctoon_mut_val *ctoon_mut_str(ctoon_mut_doc *doc, const char *str);
ctoon_mut_val *ctoon_mut_arr(ctoon_mut_doc *doc);
ctoon_mut_val *ctoon_mut_obj(ctoon_mut_doc *doc);

bool ctoon_mut_arr_append(ctoon_mut_val *arr, ctoon_mut_val *item);
bool ctoon_mut_obj_put(ctoon_mut_val *obj, ctoon_mut_val *key, ctoon_mut_val *val);

/* convert between immutable and mutable */
ctoon_mut_doc *ctoon_doc_mut_copy(ctoon_doc *doc, const ctoon_alc *alc);
ctoon_doc     *ctoon_mut_doc_imut_copy(ctoon_mut_doc *doc, const ctoon_alc *alc);

Complexity

Operation Time Notes
ctoon_read / ctoon_read_json O(n) n = input bytes
ctoon_write / ctoon_doc_to_json O(n) zero extra copy for immutable doc
ctoon_arr_get(arr, i) O(1) direct index into flat arena
ctoon_obj_get(obj, key) O(k) linear scan; k = key count
ctoon_doc_free O(chunks) ~= O(1) arena freed in one shot

Thread Safety

Scenario Safe?
Multiple threads reading different documents Yes
Multiple threads reading the same document Yes
Building a document from multiple threads No — arena not thread-safe

Requirements

Component Requirement
C core C99, no dependencies
C++ binding C++11, header-only
Python binding Python 3.9+, nanobind >= 2.0, CMake 3.19+
Go binding Go 1.21+, CGo
MATLAB binding MATLAB R2014b+, C compiler for MEX
CLI C++17

License

MIT — see LICENSE.

Related