Skip to content

High-performance FFI bindings between Bebop serialization and V language for IIoT edge computing

License

Unknown, Unknown licenses found

Licenses found

Unknown
LICENSE
Unknown
LICENSE.txt
Notifications You must be signed in to change notification settings

hyperpolymath/bebop-v-ffi

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

34 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

License = Bebop-V-FFI

High-performance FFI bindings between Bebop binary serialization and the V programming language for Industrial IoT edge computing

RSR Bronze TPCF Perimeter 3 IIoT Edge Kaldor Integration

Overview

bebop-v-ffi provides a small, explicit FFI boundary that exposes the Bebop binary serialization format to the V programming language.

The project defines a stable C ABI (the "FFI contract") and allows multiple implementations behind it (initially Zig; Rust welcome), so that V applications can decode and encode Bebop messages without reimplementing the wire format.

This library is a core component of the Kaldor IIoT ecosystem, enabling efficient message passing between resource-constrained edge devices (ESP32-C6, RISC-V microcontrollers) and backend services.

Why "FFI" (not "bridge")?

This project is deliberately named bebop-v-ffi because the hard part here is not "connecting two projects" — it’s defining and maintaining a correct Foreign Function Interface.

An FFI boundary is where you must be explicit about things that higher-level code usually hides:

  • ABI stability - calling conventions, alignment/padding

  • Ownership and lifetimes - who frees what, when

  • Error propagation - how failures cross the boundary

  • Message framing - for networked data

Getting any of those wrong can produce silent corruption rather than a clean crash.

So this repo treats the C ABI as the core deliverable: a small, boring, stable contract that V can rely on, while different implementations can evolve underneath without changing user code.

Current Status

Component Status Notes

ABI header

drafted

include/bebop_v_ffi.h

V bindings

drafted

v/bebop_bridge.v

Zig implementation

placeholder skeleton

implementations/zig

Rust implementation

help wanted

implementations/rust/README.md

Example framing

included

v/examples/iiot_server.v, v/examples/iiot_client.v

Quickstart (conceptual)

  1. Generate C bindings from schema with bebopc --lang c (see scripts/gen_c_from_schema.sh)

  2. Build an implementation (Zig today)

  3. Use the bebop_bridge.v module in v/ directory from your V app

Why Bebop?

Bebop is a schema-based binary serialization format optimized for real-time applications:

  • 10-100x faster than Protocol Buffers, MessagePack, and JSON

  • Zero-copy deserialization - reads directly from wire format

  • Tiny code generation - ~50KB for full runtime (ideal for microcontrollers)

  • Schema evolution - backwards-compatible message updates

  • No reflection - compile-time code generation, no runtime overhead

Benchmark: 1M messages (100-byte payload)
┌────────────────┬───────────┬─────────────┐
│ Format         │ Serialize │ Deserialize │
├────────────────┼───────────┼─────────────┤
│ Bebop          │ 12ms      │ 8ms         │
│ FlatBuffers    │ 45ms      │ 15ms        │
│ Protocol Bufs  │ 180ms     │ 220ms       │
│ MessagePack    │ 350ms     │ 410ms       │
│ JSON           │ 890ms     │ 1,200ms     │
└────────────────┴───────────┴─────────────┘

Why V?

V is a systems programming language designed for reliability and performance:

  • Compiles to native code - C backend, ~1MB binaries

  • No hidden allocations - predictable memory usage

  • No garbage collector pauses - manual memory management option

  • C interop - seamless FFI with existing C libraries

  • Fast compilation - ~1 second for most projects

  • Ideal for embedded - targets ESP32, ARM, RISC-V

V fills the gap between Rust’s complexity and C’s lack of safety, making it perfect for IIoT firmware development.

Why This FFI?

Kaldor IIoT needs to move telemetry data (temperature, humidity, loom status, spinning metrics) between:

  • Edge devices (ESP32-C6 running V firmware)

  • Gateway nodes (Raspberry Pi, RISC-V SBCs)

  • Backend services (Deno/TypeScript, Rust WASM)

Bebop-V-FFI provides the glue layer, enabling:

┌─────────────────┐     Bebop Binary      ┌─────────────────┐
│  V Firmware     │◄────────────────────►│  Deno Backend   │
│  (ESP32-C6)     │    ~8 bytes/msg       │  (TypeScript)   │
└────────┬────────┘                       └────────┬────────┘
         │                                         │
         │  Matter Protocol (Thread mesh)          │  WASM Compute
         │                                         │
         ▼                                         ▼
┌─────────────────┐                       ┌─────────────────┐
│  Gateway Node   │                       │  TimescaleDB    │
│  (RISC-V SBC)   │                       │  (Time-series)  │
└─────────────────┘                       └─────────────────┘

Key Features

  • Zero-Copy Parsing - Reads Bebop messages without intermediate allocations

  • Code Generation - V source generated from .bop schema files

  • Memory Safe - Bounds checking, no buffer overflows

  • Tiny Footprint - <20KB compiled FFI layer

  • Cross-Platform - Linux, macOS, Windows, embedded targets

  • Thread Safe - No global state, safe for concurrent use

  • Offline-First - Works completely air-gapped

  • RSR Compliant - Rhodium Standard Repository Bronze tier

Quick Start

Installation

# Clone repository
git clone https://github.com/hyperpolymath/bebop-v-ffi.git
cd bebop-v-ffi

# Build the FFI library
v build -prod src/

# Run tests
v test tests/

# Install Bebop compiler (for schema compilation)
# See: https://bebop.sh/guide/installation/

Define Schema

Create a .bop schema file:

// schemas/telemetry.bop
struct SensorReading {
    uint32 device_id;
    uint64 timestamp_ms;
    float32 temperature_c;
    float32 humidity_pct;
    uint8 status_flags;
}

message LoomStatus {
    1 -> uint32 loom_id;
    2 -> string pattern_name;
    3 -> uint32 picks_completed;
    4 -> uint32 picks_total;
    5 -> float32 efficiency_pct;
}

Generate V Code

# Generate V bindings from Bebop schema
bebop --generator v --input schemas/telemetry.bop --output src/telemetry.v

Use in V

import bebop_ffi
import telemetry

fn main() {
    // Create a sensor reading
    reading := telemetry.SensorReading{
        device_id: 0x1001
        timestamp_ms: u64(time.now().unix_milli())
        temperature_c: 23.5
        humidity_pct: 65.2
        status_flags: 0x01
    }

    // Serialize to Bebop binary (zero-copy)
    buffer := bebop_ffi.encode(reading)
    println('Serialized: ${buffer.len} bytes')

    // Send over network/Matter protocol...

    // Deserialize (zero-copy)
    decoded := bebop_ffi.decode[telemetry.SensorReading](buffer)
    println('Temperature: ${decoded.temperature_c}°C')
}

Architecture

┌─────────────────────────────────────────────────────────┐
│                     User Application                     │
│                    (V source code)                       │
└─────────────────────────┬───────────────────────────────┘
                          │
                          ▼
┌─────────────────────────────────────────────────────────┐
│                Generated V Bindings                      │
│        (from .bop schemas via bebop compiler)           │
├─────────────────────────────────────────────────────────┤
│  struct SensorReading { ... }                           │
│  fn encode(msg) -> []u8                                 │
│  fn decode[T](buf) -> T                                 │
└─────────────────────────┬───────────────────────────────┘
                          │
                          ▼
┌─────────────────────────────────────────────────────────┐
│                   Bebop-V-FFI Core                       │
│              (this library - V + C)                     │
├─────────────────────────────────────────────────────────┤
│  - Buffer management (arena allocator)                  │
│  - Endianness handling                                  │
│  - Bounds checking                                      │
│  - Zero-copy view creation                              │
└─────────────────────────┬───────────────────────────────┘
                          │
                          ▼
┌─────────────────────────────────────────────────────────┐
│                    Bebop Runtime                         │
│              (C library, ~50KB compiled)                │
└─────────────────────────────────────────────────────────┘

Design Rationale

Why V instead of Rust for firmware?

While Rust is superior for complex systems, V offers:

  1. Faster iteration - 1s compile times vs 30s+ for Rust

  2. Simpler mental model - No borrow checker complexity on microcontrollers

  3. Smaller binaries - Critical for ESP32’s 4MB flash

  4. C-like FFI - Direct integration with ESP-IDF SDK

Why FFI instead of pure V?

Bebop’s core runtime is C-based, battle-tested, and optimized. Wrapping it via FFI gives us:

  1. Proven serialization - No bugs in the hot path

  2. Future-proofing - Bebop updates flow through automatically

  3. Multi-language parity - Same wire format across V, Rust, TypeScript

Integration with Kaldor IIoT

Bebop-V-FFI is designed to work seamlessly with the Kaldor IIoT platform:

// firmware/main.v - ESP32-C6 Matter device
import matter
import bebop_ffi
import kaldor.telemetry

fn on_sensor_tick() {
    reading := collect_sensor_data()

    // Serialize with Bebop
    payload := bebop_ffi.encode(reading)

    // Send via Matter protocol (Thread mesh)
    matter.publish("kaldor/telemetry", payload)
}

fn collect_sensor_data() telemetry.SensorReading {
    return telemetry.SensorReading{
        device_id: matter.get_device_id()
        timestamp_ms: u64(time.now().unix_milli())
        temperature_c: read_temperature_sensor()
        humidity_pct: read_humidity_sensor()
        status_flags: get_device_status()
    }
}

Kaldor Message Types

| Message Type | Size | Use Case | |--------------|------|----------| | SensorReading | 17 bytes | Environmental telemetry | | LoomStatus | ~40 bytes | Weaving progress tracking | | SpinnerMetrics | 24 bytes | Spinning node performance | | AlertEvent | ~60 bytes | Fault notifications | | GossipHeartbeat | 12 bytes | Mesh network health |

Documentation

Standards Compliance

RSR Framework: Bronze Tier

Bebop-V-FFI meets Rhodium Standard Repository (RSR) Bronze tier requirements:

  • Type safety (V compile-time guarantees)

  • Memory safety (bounds checking, no raw pointers in public API)

  • Offline-first (no network dependencies)

  • Complete documentation

  • .well-known/ directory

  • Build system (justfile)

  • CI/CD pipeline

TPCF: Perimeter 3 (Community Sandbox)

This project uses the Tri-Perimeter Contribution Framework (TPCF):

  • Perimeter 1: Core maintainers only

  • Perimeter 2: Trusted contributors

  • Perimeter 3: Community Sandbox - Open to all

All contributions are welcome! See CONTRIBUTING.md.

Building from Source

Prerequisites

  • V compiler 0.4.4+ (v version)

  • C compiler (GCC 11+ or Clang 14+)

  • Bebop compiler (bebopc --version)

  • just command runner

Build Commands

# Build library
just build

# Build with optimizations
just build-release

# Run tests
just test

# Generate V bindings from schemas
just codegen

# Check RSR compliance
just validate-rsr

# Build for ESP32-C6 target
just build-esp32

Testing

# Run all tests
v test tests/

# Run with verbose output
v test tests/ -stats

# Run specific test
v test tests/test_encode.v

# Benchmark serialization
v run benchmarks/bench_encode.v

Performance

| Operation | Time (1M msgs) | Memory | |-----------|----------------|--------| | Encode SensorReading | 8ms | 0 allocs | | Decode SensorReading | 5ms | 0 allocs | | Encode LoomStatus | 12ms | 1 alloc (string) | | Decode LoomStatus | 9ms | 1 alloc (string) |

Binary sizes:

  • FFI library: ~18KB (stripped)

  • Full firmware (with Matter): ~280KB

  • Bebop runtime: ~50KB

Security

See SECURITY.md for:

  • Supported versions

  • Vulnerability reporting process

  • Security best practices

License

SPDX-License-Identifier: PMPL-1.0 OR LicenseRef-Palimpsest-0.8`

Dual licensed under your choice of:

  • PMPL-1.0-or-later - GNU Affero General Public License

  • Palimpsest License v0.8 - Community ownership with reversibility

  • kaldor-iiot - Parent IIoT platform

  • bunsenite - Nickel config parser with similar FFI architecture

  • Bebop - Binary serialization format

  • V Language - Systems programming language

Roadmap

See ROADMAP.adoc for the full development roadmap including:

  • Phase 1: Core FFI implementation and schema codegen

  • Phase 2: Release and packaging (crates.io, vpkg)

  • Phase 3: Next-gen Rust-V-Bebop hybrid implementation

Help Wanted: Rust Implementation (plug-compatible)

I’d love a contributor to implement the same ABI in Rust (staticlib/cdylib), so V users can choose Zig or Rust underneath.

What you’d do:

  • Implement the functions in include/bebop_v_ffi.h

  • Use VBytes (ptr+len) for all strings/bytes (do not assume NUL-terminated data)

  • Match the framing + golden test vectors under test-vectors/

Good first PR:

  • bebop_decode_sensor_reading() for SensorReading

  • bebop_ctx_new() / bebop_ctx_free() and bebop_free_reading()

See docs/60-contributing-implementations.adoc for notes and pitfalls.

Acknowledgments


Version: 0.1.0
Status: Active Development
Last Updated: 2025-12-24

"Microseconds matter when you’re weaving the future."

About

High-performance FFI bindings between Bebop serialization and V language for IIoT edge computing

Topics

Resources

License

Unknown, Unknown licenses found

Licenses found

Unknown
LICENSE
Unknown
LICENSE.txt

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Sponsor this project

Packages

No packages published

Contributors 2

  •  
  •