Skip to content

πŸ¦β€πŸ”₯ Community-driven Swift implementation of TOON

License

Notifications You must be signed in to change notification settings

toon-format/toon-swift

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

23 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

TOON Format for Swift

CI Swift Version SPEC v3.0 License: MIT

Compact, human-readable serialization format for LLM contexts with 30-60% token reduction vs JSON. Combines YAML-like indentation with CSV-like tabular arrays. Full compatibility with the official TOON specification.

Key Features: Minimal syntax β€’ Tabular arrays for uniform data β€’ Array length validation β€’ Swift 6.0+ β€’ Configurable delimiters β€’ Key folding / Path expansion support β€’ Linux compatibility.

LLM tokens are expensive, and JSON is verbose. TOON saves tokens while remaining human-readable by using indentation for structure and a tabular format for uniform data:

JSON:

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

TOON:

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

For full details on TOON's design, benchmarks, and specification, see the TOON specification.

Features

TOONEncoder

TOONEncoder conforms to TOON specification version 3.0 (2025-11-24) and implements the following features:

  • Canonical number formatting (no trailing zeros, no leading zeros except 0; -0 normalized to 0 by default)
  • Correct escape sequences for strings (\\, \", \n, \r, \t)
  • Three delimiter types: comma (default), tab, pipe
  • Array length validation
  • Object key order preservation
  • Array order preservation
  • Tabular format for uniform object arrays
  • Inline format for primitive arrays
  • Expanded list format for nested structures
  • Key folding to collapse single-key object chains into dotted paths
  • Configurable flatten depth to limit the depth of key folding
  • Collision avoidance so folded keys never collide with existing sibling keys
  • Configurable encoding limits for security

TOONDecoder

TOONDecoder conforms to TOON specification version 3.0 (2025-11-24) and implements the following features:

  • Correct escape sequence parsing (\\, \", \n, \r, \t)
  • Three delimiter types: comma (default), tab, pipe
  • Array length validation
  • Tabular format parsing with field headers
  • Inline format for primitive arrays
  • Expanded list format for nested structures
  • Path expansion to unfold dotted keys into nested objects (inverse of key folding)
  • Detailed error reporting with line numbers
  • Configurable decoding limits for security

Requirements

  • Swift 6.0+ / Xcode 16+
  • iOS 13.0+ / macOS 10.15+ / watchOS 6.0+ / tvOS 13.0+ / visionOS 1.0+ / Linux

Installation

Swift Package Manager

Add the following to your Package.swift file:

dependencies: [
    .package(url: "https://github.com/toon-format/toon-swift.git", from: "0.3.0")
]

Then add the dependency to your target:

.target(name: "YourTarget", dependencies: ["ToonFormat"])

Usage

Quick Start

import ToonFormat

struct User: Codable {
    let id: Int
    let name: String
    let tags: [String]
    let active: Bool
}

// Encoding
let user = User(
    id: 123,
    name: "Ada",
    tags: ["reading", "gaming"],
    active: true
)

let encoder = TOONEncoder()
let data = try encoder.encode(user)
print(String(data: data, encoding: .utf8)!)
// id: 123
// name: Ada
// tags[2]: reading,gaming
// active: true

// Decoding
let decoder = TOONDecoder()
let decoded = try decoder.decode(User.self, from: data)
print(decoded.name) // "Ada"

Object Key Ordering

TOONEncoder preserves the field order defined by Encodable types. When encoding Swift Dictionary values, keys are sorted lexicographically. This helps ensure deterministic output while preserving semantics of encoded data structures.

Note

Dictionary key ordering is best-effort and relies on a heuristic that may change with Swift internals.

struct ShoppingList: Codable {
    let name: String
    let itemsAndCounts: [String: Int]
}

let list = ShoppingList(
    name: "Groceries",
    itemsAndCounts: ["cherries": 3, "apple": 1, "banana": 2]
)

let encoder = TOONEncoder()
let data = try encoder.encode(list)
print(String(data: data, encoding: .utf8)!)
// name: Groceries    /* name comes first because it is declared first in the struct */
// itemsAndCounts:
//   apple: 1         /* keys in dictionary are sorted */
//   banana: 2
//   cherries: 3

Custom Delimiters

Use tab or pipe delimiters for additional token savings:

struct Item: Codable {
    let sku: String
    let name: String
    let qty: Int
    let price: Double
}

let items = [
    Item(sku: "A1", name: "Widget", qty: 2, price: 9.99),
    Item(sku: "B2", name: "Gadget", qty: 1, price: 14.5)
]

let encoder = TOONEncoder()
encoder.delimiter = .tab  // or .pipe

let data = try encoder.encode(["items": items])

Output with tab delimiter:

items[2	]{sku	name	qty	price}:
  A1	Widget	2	9.99
  B2	Gadget	1	14.5

Output with pipe delimiter:

items[2|]{sku|name|qty|price}:
  A1|Widget|2|9.99
  B2|Gadget|1|14.5

Numeric Normalization

TOONEncoder defaults to canonical normalization that matches the spec and the reference JavaScript implementation. You can override this behavior when you need to preserve negative zero or handle non-finite values explicitly.

let encoder = TOONEncoder()
encoder.negativeZeroEncodingStrategy = .preserve
encoder.nonConformingFloatEncodingStrategy = .convertToString(
    positiveInfinity: "Infinity",
    negativeInfinity: "-Infinity",
    nan: "NaN"
)

Tabular Arrays

Arrays of objects with identical primitive fields use an efficient tabular format:

struct Item: Codable {
    let sku: String
    let qty: Int
    let price: Double
}

let items = [
    Item(sku: "A1", qty: 2, price: 9.99),
    Item(sku: "B2", qty: 1, price: 14.5)
]

let encoder = TOONEncoder()
let data = try encoder.encode(["items": items])

Output:

items[2]{sku,qty,price}:
  A1,2,9.99
  B2,1,14.5

Arrays of Arrays

For arrays containing primitive inner arrays:

let pairs = [[1, 2], [3, 4]]

let encoder = TOONEncoder()
let data = try encoder.encode(["pairs": pairs])

Output:

pairs[2]:
  - [2]: 1,2
  - [2]: 3,4

Key Folding

Key folding collapses single-key nested objects into dotted paths, reducing indentation and token count:

struct Config: Codable {
    struct Database: Codable {
        struct Connection: Codable {
            let host: String
            let port: Int
        }
        let connection: Connection
    }
    let database: Database
}

let config = Config(
    database: .init(
        connection: .init(host: "localhost", port: 5432)
    )
)

let encoder = TOONEncoder()
encoder.keyFolding = .safe
let data = try encoder.encode(config)

Without key folding:

database:
  connection:
    host: localhost
    port: 5432

Output with key folding (encoder.keyFolding = .safe):

database.connection:
  host: localhost
  port: 5432

Encoding Limits

Protect against stack overflow from deeply nested structures:

let encoder = TOONEncoder()
encoder.limits = TOONEncoder.EncodingLimits(maxDepth: 64)
Limit Default Description
maxDepth 32 Maximum nesting depth

Use .unlimited for trusted data only.

Decoding Limits

Protect against malicious or malformed input:

let decoder = TOONDecoder()
decoder.limits = TOONDecoder.DecodingLimits(
    maxInputSize: 1024 * 1024,  // 1 MB
    maxDepth: 64,
    maxObjectKeys: 1000,
    maxArrayLength: 10000
)
Limit Default Description
maxInputSize 10 MB Maximum input size in bytes
maxDepth 32 Maximum nesting depth
maxObjectKeys 10,000 Maximum keys per object
maxArrayLength 100,000 Maximum elements per array

Use .unlimited for trusted data only.

Version Information

Check the supported TOON specification version:

print(toonSpecVersion) // "3.0"

Contributing

Contributions are welcome! Please read our Contributing Guide for details on how to get started, coding standards, and the process for submitting pull requests.

Before contributing, please review:

Code of Conduct

This project follows the Contributor Covenant Code of Conduct. By participating, you are expected to uphold this code. Please report unacceptable behavior to hello@johannschopplich.com.

Project Status

This library implements TOON specification version 3.0 (2025-11-24) with full encoding and decoding support.

See CONTRIBUTING.md for detailed guidelines.

Documentation

License

MIT License – see LICENSE.md for details

About

πŸ¦β€πŸ”₯ Community-driven Swift implementation of TOON

Topics

Resources

License

Code of conduct

Contributing

Stars

Watchers

Forks

Contributors 4

  •  
  •  
  •  
  •  

Languages