Skip to main content

FFI Interface

The FFI (Foreign Function Interface) layer enables communication between the Rust core (chameleon-core) and Go runtime (chameleon) via a stable C ABI. This boundary handles schema parsing, validation, SQL generation, and memory management across language boundaries.

Overview

The FFI bridge provides:
  1. Schema parsing - .cham → JSON AST
  2. Schema validation - Type checking with structured errors
  3. SQL generation - Queries and migrations
  4. Memory management - Safe allocation/deallocation across boundaries
  5. Version checking - Ensure Rust/Go compatibility

Architecture

Data flow:
  1. Go calls C function via cgo
  2. C function marshals to Rust (UTF-8 strings)
  3. Rust processes and returns JSON (serialized via serde_json)
  4. C function returns pointer to Go
  5. Go deserializes JSON and frees Rust memory

C ABI Functions

Location: chameleon-core/src/ffi/mod.rs

Parse Schema

Parameters:
  • input - Null-terminated .cham source code
  • error_out - Output pointer for error JSON (if any)
Returns:
  • JSON AST on success (caller must free with chameleon_free_string)
  • NULL on failure (error_out contains error JSON)
Example:

Validate Schema

Parameters:
  • input - Null-terminated .cham source code
  • error_out - Output pointer for validation result JSON
Returns:
  • ChameleonResult::Ok - Schema is valid
  • ChameleonResult::ParseError - Syntax error
  • ChameleonResult::ValidationError - Type check failed
  • ChameleonResult::InternalError - Unexpected error
Result JSON (success):
Result JSON (failure):

Generate SQL

Parameters:
  • query_json - Query specification (JSON)
  • schema_json - Schema AST (JSON)
  • error_out - Output pointer for generated SQL (JSON)
Returns:
  • ChameleonResult::Ok - SQL generated (error_out contains result)
  • ChameleonResult::ValidationError - Invalid query
  • ChameleonResult::InternalError - Unexpected error

Generate Migration

Parameters:
  • schema_json - Schema AST (JSON)
  • error_out - Output pointer for migration SQL
Returns:
  • ChameleonResult::Ok - Migration SQL in error_out
  • ChameleonResult::ValidationError - Invalid schema
  • ChameleonResult::InternalError - Unexpected error

Free String

Parameters:
  • s - String allocated by Rust (from any FFI function)
Safety:
  • Safe to call with NULL (no-op)
  • Must be called for every non-NULL pointer returned by Rust
  • Never call twice on the same pointer (double-free)

Version

Returns:
  • Static string with Rust core version (e.g., “0.1.0-beta”)
  • Never needs to be freed (static lifetime)

Result Codes

Usage in Go:

Go Bindings

Location: chameleon/internal/ffi/bindings.go

CGO Setup

LDFLAGS explanation:
  • -L/usr/local/lib - Library search path
  • -Wl,-rpath,/usr/local/lib - Runtime library path (embeds path in binary)
  • -lchameleon - Link against libchameleon.so (Linux) or libchameleon.dylib (macOS)

ParseSchema

Memory management:
  1. C.CString(input) - Allocate C string (must free with C.free)
  2. C.chameleon_parse_schema() - Call Rust (returns Rust-allocated string)
  3. C.GoString(cResult) - Copy to Go string
  4. C.chameleon_free_string(cResult) - Free Rust allocation

ValidateSchemaRaw

Version

Note: No need to free - static string in Rust

Building libchameleon.so

Prerequisites

Build Steps

Install System-Wide

Linux:
macOS:

Verify Installation

Cargo Configuration

Location: chameleon-core/Cargo.toml
Crate types:
  • rlib - Rust static library (for Rust consumers)
  • staticlib - C-compatible static library (.a)
  • cdylib - C-compatible dynamic library (.so, .dylib, .dll)

C Header Generation

Location: chameleon-core/build.rs:22
Generated header (include/chameleon.h):

Linking from Go

Development Build

Production Build

Docker Build

Memory Management

Ownership Rules

Common Pitfalls

❌ Double-free:
❌ Memory leak:
✅ Correct:

Performance Characteristics

Total parse overhead:
  • Small schema (5 entities): ~500μs
  • Medium schema (20 entities): ~2ms
  • Large schema (100 entities): ~10ms
Comparison to pure Go parser:
  • FFI overhead: +30% (but Rust parser is 3x faster)
  • Net result: 2x faster than pure Go

Testing

Location: chameleon-core/src/ffi/mod.rs:471

Rust Tests

Go Tests

Location: chameleon/internal/ffi/bindings_test.go (hypothetical)

Troubleshooting

Library Not Found

Error:
Solution:

Symbol Not Found

Error:
Causes:
  • Rust library not built with cdylib crate type
  • Function not marked #[no_mangle]
  • Header out of sync with implementation
Solution:

Version Mismatch

Error:
Solution:

See Also