Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Serialization Formats

CASM programs can be serialized in two formats: JSON (human-readable) and Binary (compact). This chapter explains both formats and when to use each.

JSON Format (.casm)

The JSON format is the primary, human-readable serialization format for CASM programs.

Characteristics

  • Human-readable: Easy to read, write, and debug
  • Text-based: Can be version-controlled with git
  • Portable: Works across all platforms
  • Larger size: More verbose than binary format
  • Slower parsing: JSON parsing has overhead

File Extension

.casm

Example

{
  "version": "0.1",
  "functions": {
    "main": {
      "params": [],
      "locals": [],
      "body": [
        {"op": "push_int", "value": 42},
        {"op": "cap_call", "name": "io.print", "argc": 1},
        {"op": "ret"}
      ]
    }
  },
  "manifest": {
    "permissions": ["io.print"]
  }
}

When to Use

✅ Use JSON when:

  • Developing and debugging programs
  • Hand-writing CASM code
  • Generating CASM from tools
  • Version controlling bytecode
  • Sharing examples and documentation
  • Learning CASM

❌ Avoid JSON when:

  • Deploying to production (use binary)
  • Size matters (embedded systems, network transfer)
  • Performance is critical

Binary Format (.casmb)

The binary format uses MessagePack for compact, efficient serialization.

Characteristics

  • Compact: 30-50% smaller than JSON
  • Fast: Faster to parse and serialize
  • Binary: Not human-readable
  • Portable: MessagePack is cross-platform

File Extension

.casmb

Structure

The binary format uses MessagePack to serialize the same structure as JSON:

┌─────────────────────────────────┐
│ MessagePack Binary Data         │
│                                 │
│ Same structure as JSON:         │
│ - version (string)              │
│ - functions (map)               │
│ - lang (optional string)        │
│ - manifest (optional map)       │
└─────────────────────────────────┘

When to Use

✅ Use Binary when:

  • Deploying to production
  • Distributing compiled programs
  • Minimizing file size
  • Optimizing load time
  • Embedding in other formats

❌ Avoid Binary when:

  • Debugging or development
  • Need to inspect bytecode
  • Version controlling (use JSON)

Format Detection

The Crush VM automatically detects the format based on file extension:

ExtensionFormatAuto-detected
.casmJSON✓
.casmbBinary (MessagePack)✓
OtherJSON (default)✓

Example

# JSON format (auto-detected)
exo run program.casm

# Binary format (auto-detected)
exo run program.casmb

# Explicit format specification
exo run --format=json program.txt
exo run --format=binary program.bin

Converting Between Formats

JSON to Binary

# Using crush-cli
exo compile program.casm --output program.casmb

# Or programmatically in Rust
use casm::{Program, Format};

let program = Program::load("program.casm")?;
program.save("program.casmb")?;  // Auto-detects binary format

Binary to JSON

# Using crush-cli
crush decompile program.casmb --output program.casm

# Or programmatically
let program = Program::load("program.casmb")?;
program.save("program.casm")?;  // Auto-detects JSON format

Size Comparison

Example program sizes:

ProgramJSON (.casm)Binary (.casmb)Savings
Hello World450 bytes180 bytes60%
Fibonacci1.2 KB650 bytes46%
Complex App50 KB28 KB44%

Binary format typically saves 40-60% of file size.

Performance Comparison

Parsing performance (approximate):

FormatParse TimeSerialize Time
JSON100% (baseline)100% (baseline)
Binary40% (2.5x faster)30% (3.3x faster)

Binary format is 2-3x faster to parse and serialize.

Rust API

Loading Programs

#![allow(unused)]
fn main() {
use casm::{Program, Format};
use std::path::Path;

// Auto-detect format from extension
let program = Program::load(Path::new("program.casm"))?;

// Explicit format
let data = std::fs::read("program.casm")?;
let program = Program::deserialize(&data, Format::Json)?;
}

Saving Programs

#![allow(unused)]
fn main() {
// Auto-detect format from extension
program.save(Path::new("output.casmb"))?;

// Explicit format
let data = program.serialize(Format::Binary)?;
std::fs::write("output.casmb", data)?;
}

Format Enum

#![allow(unused)]
fn main() {
pub enum Format {
    Json,   // Human-readable (.casm)
    Binary, // Compact binary (.casmb)
}

impl Format {
    pub fn from_path(path: &Path) -> Self {
        match path.extension().and_then(|e| e.to_str()) {
            Some("casmb") => Format::Binary,
            _ => Format::Json,
        }
    }
}
}

Best Practices

Development Workflow

  1. Write in JSON during development
  2. Version control JSON files
  3. Compile to binary for production
  4. Distribute binary to end users

Example Workflow

# 1. Develop in JSON
vim program.casm

# 2. Test with JSON
exo run program.casm

# 3. Commit JSON to git
git add program.casm
git commit -m "Add new feature"

# 4. Build binary for release
exo compile program.casm --output program.casmb

# 5. Distribute binary
cp program.casmb /usr/local/bin/myapp.casmb

CI/CD Pipeline

# .github/workflows/build.yml
- name: Compile CASM
  run: |
    exo compile src/*.casm --output-dir dist/
    
- name: Upload artifacts
  uses: actions/upload-artifact@v2
  with:
    name: bytecode
    path: dist/*.casmb

Metadata Preservation

Both formats preserve all metadata:

// JSON format
{
  "op": "push_int",
  "value": 42,
  "lang": "python",
  "meta": {
    "file": "script.py",
    "line": 10
  }
}
// Binary format (MessagePack)
// Same data, just binary-encoded

Metadata is fully preserved in both formats, so debugging information is available even in production binaries.

Compression

For even smaller sizes, compress the binary format:

# gzip compression
gzip program.casmb
# Result: program.casmb.gz (typically 60-70% of .casmb size)

# brotli compression (better)
brotli program.casmb
# Result: program.casmb.br (typically 50-60% of .casmb size)

Combined savings:

FormatSizevs JSON
JSON100%-
Binary45%55% smaller
Binary + gzip30%70% smaller
Binary + brotli25%75% smaller

Validation

Both formats are validated on load:

#![allow(unused)]
fn main() {
match Program::load("program.casm") {
    Ok(program) => println!("Valid CASM program"),
    Err(e) => eprintln!("Invalid CASM: {}", e),
}
}

Common validation errors:

  • Missing required fields (version, functions)
  • Invalid instruction opcodes
  • Malformed JSON/MessagePack
  • Type mismatches

Future Formats

Potential future serialization formats:

  • WebAssembly: For browser execution
  • Protobuf: For RPC and network protocols
  • CBOR: Alternative binary format
  • Custom binary: Optimized Crush-specific format

Summary

AspectJSONBinary
Extension.casm.casmb
EncodingJSONMessagePack
Readable✓✗
SizeLargerSmaller (40-60% savings)
SpeedSlowerFaster (2-3x)
Use CaseDevelopment, debuggingProduction, distribution
Version Control✓ Recommended✗ Not recommended
Metadata✓ Preserved✓ Preserved

Recommendation: Use JSON for development, binary for production.