Schema System
Cerulion Core’s schema system provides automatic type generation from YAML schema files. This build-time code generation ensures type safety, consistency across languages, and eliminates manual struct definitions.What is the Schema System?
The schema system is a build-time code generation architecture that transforms YAML schema definitions into type-safe message structs. Instead of manually writing struct definitions, you define your message types once in YAML, and Cerulion Core generates the code automatically during compilation. Think of it as a compiler for your data types - you write the specification, and the system produces optimized, type-safe code that integrates seamlessly with Cerulion Core’s transport and serialization layers.Design Philosophy
Single Source of Truth
Define types once in YAML, use everywhere. No duplication between languages or components.
Type Safety
Generated code is type-checked at compile time (Rust) or runtime (Python/C++). Prevents compatibility errors.
Consistency
Same schema produces identical binary layouts across all languages. Guaranteed interoperability.
Zero Boilerplate
No manual struct definitions. Code generation happens automatically during build.
Memory Layout Control
All types use
repr(C) for predictable memory layout. Enables zero-copy local transport.Copy Semantics
Generated types implement Copy, enabling efficient zero-copy shared memory transport.
Schema Format
Cerulion Core supports two schema formats: V2 format (recommended) and legacy format (backward compatible).V2 Format (Recommended)
V2 format uses inline field syntax inspired by ROS2:type[size] name:
The inline syntax
float[20] positions: is much more concise than the legacy format’s separate name, type, and size fields.Key Features
Multi-Schema Files Define multiple related types in one file:Legacy Format
Legacy format is still supported for backward compatibility:The parser automatically detects format version. V2 format is recommended for new schemas, but legacy format continues to work.
Build Process Architecture
Code generation happens automatically duringcargo build:
Build Process Steps
- Schema Discovery:
build.rsscansschemas/directory for YAML files - Parsing: Parser detects format version (V2 vs legacy) and parses schemas
- Validation: Type checker validates field types and resolves dependencies
- Code Generation: Generates Rust structs with appropriate derives and layout
- Output: Writes generated code to
OUT_DIR(build output directory) - Inclusion: Source code uses
include!()macro to include generated code - Compilation: Rust compiler validates generated code with full type checking
Generated files are placed in
target/debug/build/cerulion-*/out/ and included via include!(concat!(env!("OUT_DIR"), "/sensor_data_generated.rs")).Generated Code Structure
Simple Message
Schema:Clone, Copy: Enables efficient zero-copy transportDebug: Essential for development and debuggingrepr(C): Ensures predictable memory layout across languages- All fields public: Direct access for high-performance code
Arrays with Partial Naming
Schema:Partial naming lets you name only the array indices you know, while still accessing all elements. This is ideal for robot joints where you know some joint names but not all.
Nested Custom Types
Schema:Type Mappings
Schema types map to language-specific types with consistent memory layout:| Schema Type | Rust Type | Size | Copy? |
|---|---|---|---|
bool | bool | 1 | ✅ |
int8 | i8 | 1 | ✅ |
int16 | i16 | 2 | ✅ |
int32 | i32 | 4 | ✅ |
int64 | i64 | 8 | ✅ |
uint8 | u8 | 1 | ✅ |
uint16 | u16 | 2 | ✅ |
uint32 | u32 | 4 | ✅ |
uint64 | u64 | 8 | ✅ |
float | f32 | 4 | ✅ |
double | f64 | 8 | ✅ |
string_fixed[N] | [u8; N] | N | ✅ |
T[N] | [T; N] | N×sizeof(T) | ✅ |
All generated types implement
Copy, making them compatible with Cerulion Core’s zero-copy local transport and efficient network serialization.Multi-Language Support
The schema system is designed for multi-language code generation:| Language | Status | Generator | Binary Compatible |
|---|---|---|---|
| Rust | ✅ Working | build.rs (automatic) | Native |
| Python | ⏳ Designed | Future script | ✅ Yes |
| C++ | ⏳ Designed | Future script | ✅ Yes |
Binary Compatibility
All languages will generate types with identical memory layouts: Rust:The
repr(C) layout ensures that the same bytes can be interpreted correctly across all languages, enabling true zero-copy multi-language communication.Integration with Cerulion Core
The schema system integrates with other Cerulion Core components:With Serialization
Generated types work seamlessly with the serialization system:- Local transport: Zero-copy via shared memory (no serialization)
- Network transport: Automatic byte serialization using
Copytrait - Type safety: Compile-time guarantees in Rust
With Publisher & Subscriber
Generated types are used directly with Publisher and Subscriber APIs:With Topic Manager
Topic Manager validates that topics use consistent message types:Best Practices
1. Use V2 Format for New Schemas
2. Group Related Types in Multi-Schema Files
- Clear dependencies between types
- Easier to maintain
- Reduces file switching
- Single import for related types
3. Use Shared Index Groups for Arrays
4. Document Your Schemas
5. Keep Types Small and Focused
- Easier to version independently
- More reusable across different contexts
- Lower memory overhead when only subset needed
- Clearer semantic meaning
Memory Layout and Performance
Memory Alignment
Generated types userepr(C) for predictable memory layout:
- Consistent layout across compiler versions
- Binary compatibility with C/C++
- Predictable serialization size
- Efficient zero-copy shared memory access
Copy Semantics
All generated types implementCopy:
- Works with iceoryx2 zero-copy transport
- Efficient stack allocation
- No heap allocations or reference counting
- Predictable performance
Vec, String, etc.)
For dynamic-sized data, use fixed-size arrays (
float[100]) or fixed-size strings (string_fixed[256]) instead.