Module :: unilang
Zero-overhead command framework with compile-time command registration
Value Proposition
unilang processes command definitions at compile-time, generating optimized static command registries that provide O(1) command lookups with zero runtime overhead and zero additional dependencies for downstream crates. This approach delivers:
- 50x faster command resolution compared to runtime HashMap lookups (~80ns vs ~4,000ns)
- Compile-time validation of all command definitions and arguments
- Smaller binary size through static analysis and dead code elimination
- SIMD acceleration for parsing with 4-25x performance improvements
- Zero memory allocations for command lookup operations
Architecture Overview
Compile-Time Processing:
YAML definitions → build.rs → Static command maps → Zero-cost lookups
Runtime Execution:
Command string → O(1) static lookup → Validated execution
Quick Start: Compile-Time Registration (Recommended)
Step 1: Define Commands
Create unilang.commands.yaml:
- name: ".greet"
namespace: ""
description: "High-performance greeting command"
arguments:
- name: "name"
kind: "String"
attributes:
optional: true
default: "World"
Note: Command names should always start with a dot (.). When using build.rs for static generation, you can optionally omit the dot as it will be added automatically, but showing it here reinforces the naming convention.
Step 2: Configure Cargo.toml
The default configuration already enables compile-time YAML loading:
[]
# Multi-YAML build-time approach is enabled by default
= "0.28"
For single-file YAML approach, use:
[]
= { = "0.28", = false, = [
"enabled",
"approach_yaml_single_build" # Single YAML file at compile-time
]}
Step 3: Configure Build Script (Optional for Single-File)
If using approach_yaml_single_build, add minimal build.rs:
Note: With the default approach_yaml_multi_build feature, the build system automatically discovers all .yaml files in your project - no build.rs configuration needed!
Step 4: Zero-Cost Execution
use *;
// Include compile-time generated commands (created automatically by build system)
include!;
Performance Comparison
| Approach | Lookup Time | Memory Overhead | Binary Size |
|---|---|---|---|
| Compile-Time (Static) | ~80ns | Zero | Smaller |
| Runtime (HashMap) | ~4,000ns | Hash tables + allocations | Larger |
Benchmark Results:
- Static lookups: ~80-100ns (PHF map + zero allocations)
- Runtime lookups: ~4,000-5,000ns (HashMap + semantic analysis)
- Performance gain: 50x faster command resolution
User Guide: Integration Decisions
Decision 1: How Should I Define Commands?
⚠️ IMPORTANT: Opinionated Defaults
unilang ONLY enables Approach #2 by default. To use any other approach, you must explicitly enable its feature flag in Cargo.toml.
10 approaches are currently implemented (see full comparison):
| # | Approach | Feature Flag | Default | Lookup Speed | When to Use |
|---|---|---|---|---|---|
| 1 | YAML file → Build-time static | approach_yaml_single_build |
❌ | ~80ns | Single-file projects, compile-time validation |
| 2 | Multi-YAML files → Build-time static | approach_yaml_multi_build |
✅ DEFAULT | ~80ns | Modular projects, best DX, auto-discovery |
| 3 | YAML file → Runtime loading | approach_yaml_runtime |
❌ | ~4,200ns | Plugin configs, runtime loading |
| 4 | JSON file → Build-time static | approach_json_single_build |
❌ | ~80ns | JSON-first projects, API generation |
| 5 | Multi-JSON files → Build-time static | approach_json_multi_build |
❌ | ~80ns | Large JSON projects, modular organization |
| 6 | JSON file → Runtime loading | approach_json_runtime |
❌ | ~4,200ns | Runtime config loading, dynamic commands |
| 7 | Rust DSL (builder API) | (always available) | ✅ | ~4,200ns | Core API, prototyping, type-safe definitions |
| 8 | Rust DSL (const fn + static) | approach_rust_dsl_const |
❌ | ~80ns | High-performance DSL, compile-time |
| 18 | Hybrid (static + runtime) | approach_hybrid |
❌ | Mixed | Base CLI + plugin system |
Why Approach #2 is Default:
- Best developer experience with auto-discovery of command files
- Optimal for modular projects splitting commands across multiple files
- Compile-time validation catches errors before runtime
- Zero overhead with static registry generation
See full comparison: 21 approaches documented including planned features like declarative macros, proc macros, TOML, RON, Protobuf, GraphQL, OpenAPI.
Decision 2: How Do I Execute Commands?
// CLI applications: Avoids shell quoting issues
let result = pipeline.process_command_from_argv;
// REPL/interactive applications: String-based parsing
let result = pipeline.process_command_simple;
Decision 3: What Are the Naming Rules?
✅ Commands should start with a dot:
Decision 4: What Features Should I Enable?
Recommended: Use defaults (Approach #2 + SIMD + Enhanced REPL)
[]
= "0.28" # Multi-YAML build-time + SIMD (4-25x parsing) + Enhanced REPL
Alternative approach (JSON single-file):
[]
= { = "0.28", = false, = [
"enabled",
"approach_json_single_build" # Switch to JSON single-file approach
]}
Minimal build (Rust DSL only):
[]
= { = "0.28", = false, = ["enabled"] }
All features enabled:
[]
= { = "0.28", = ["full"] } # All 21 approaches available
Feature Architecture:
The framework uses approach-based feature flags:
- Each CLI definition approach has its own feature (e.g.,
approach_yaml_multi_build) - Approach features automatically enable required infrastructure (
static_registry,yaml_parser, etc.) - Only Approach #2 enabled by default for optimal performance and minimal binary size
- See Feature Flags Documentation for complete list
Decision 5: How Does Help Work?
Three methods available:
Decision 6: Error Handling
Unknown parameters are always detected with Levenshtein distance suggestions. This cannot be disabled and ensures command correctness.
Decision 7: Advanced Use Cases
- REPL applications: Use
enhanced_replfeature for history, completion, secure input - WASM deployment: Full framework support in browsers with SIMD acceleration
- Interactive arguments: Prompt for missing required arguments in REPL mode
CLI Aggregation: Unifying Multiple Tools
⚠️ Feature Required: multi_file (automatically enabled by default approach_yaml_multi_build)
unilang excels at aggregating multiple CLI tools into a single unified command interface. This is essential for organizations that want to consolidate developer tools while maintaining namespace isolation.
Real-World Aggregation Scenario
// Requires: approach_yaml_multi_build (default) or manually enable 'multi_file' feature
use CliBuilder;
// Aggregate multiple CLI tools into one unified command
let unified_cli = new
.static_module_with_prefix
.static_module_with_prefix
.static_module_with_prefix
.static_module_with_prefix
.detect_conflicts
.build_static;
// Usage: unified-cli .db.migrate, unified-cli .fs.copy src dest
Compile-Time Aggregation Benefits
Before Aggregation:
# Separate tools requiring individual installation and learning
After Aggregation:
# Single unified tool with consistent interface
Key Aggregation Features
Namespace Isolation
Each CLI module maintains its own command space with automatic prefix application:
Database commands become .db.migrate, .db.backup
File commands become .fs.copy, .fs.move
Network commands become .net.ping, .net.trace
No naming conflicts between modules
Conflict Detection
let registry = new
.static_module_with_prefix
.static_module_with_prefix // Conflict!
.detect_conflicts // Catches duplicate prefixes at build time
.build_static;
Help System Integration
# All aggregated commands support unified help
Advanced Aggregation Patterns
Conditional Module Loading
let registry = new
.conditional_module
.conditional_module
.build_static;
// Only includes modules when features are enabled
Multi-Source Aggregation
use PathBuf;
// Combine static commands (in-memory) and dynamic YAML loading
let registry = new
.static_module_with_prefix
.dynamic_module_with_prefix
.build_hybrid;
// Key differences:
// - static_module_with_prefix(name, prefix, Vec<CommandDefinition>)
// → Commands already in memory, fast O(1) lookup (~80-100ns)
// - dynamic_module_with_prefix(name, PathBuf, prefix)
// → Commands loaded from YAML file at runtime (~4,000ns, 50x slower)
Performance Characteristics
| Approach | Lookup Time | Memory Overhead | Conflict Detection |
|---|---|---|---|
| Compile-Time | O(1) static | Zero | Build-time |
| Runtime | O(log n) | Hash tables | Runtime |
Aggregation Scaling:
- 10 modules, 100 commands each: ~80-100ns lookup regardless of module count
- Single static map: All 1,000 commands accessible in constant time with O(1) complexity
- Namespace resolution: Zero runtime overhead with compile-time prefixing
Complete Example
See examples/practical_cli_aggregation.rs for a comprehensive demonstration showing:
- Individual CLI module definitions
- Runtime and compile-time aggregation approaches
- Namespace organization and conflict prevention
- Unified command execution patterns
- Performance comparison between approaches
# Run the complete aggregation demo
This example demonstrates aggregating database, file, network, and build CLIs into a single unified tool while maintaining type safety, performance, and usability.
Command Definition Format
Basic Command Structure
- name: ".command_name" # Required: Command identifier (must start with dot)
namespace: "" # Optional: Hierarchical organization (e.g., "math", "file")
description: "What it does" # Required: User-facing description
arguments: # Optional: Command parameters
- name: "arg_name"
kind: "String" # String, Integer, Float, Boolean, Path, etc.
attributes:
optional: false # Required by default
default: "value" # Default value if optional
Supported Argument Types
- Basic Types: String, Integer, Float, Boolean
- Path Types: Path, File, Directory
- Complex Types: Url, DateTime, Pattern (regex)
- Collections: List, Map with custom delimiters
- Special Types: JsonString, Object, Enum
Validation Rules
arguments:
- name: "count"
kind: "Integer"
validation_rules:
- Min: 1
- Max: 100
- name: "email"
kind: "String"
validation_rules:
- Pattern: "^[^@]+@[^@]+\\.[^@]+$"
- MinLength: 5
Command Execution Patterns
Standard Execution
let result = pipeline.process_command_simple;
if result.success
Batch Processing
let commands = vec!
;
let batch_result = pipeline.process_batch;
println!;
Error Handling
match pipeline.process_command_simple
Help System
unilang provides comprehensive help with three access methods:
Traditional Help Operator
Modern Help Parameter
Auto-Generated Help Commands
Feature Configuration
Core Features
[]
= "0.10" # Default: enhanced_repl + simd + enabled
Performance Optimized
[]
= { = "0.10", = ["simd", "enhanced_repl"] }
Minimal Footprint
[]
= { = "0.10", = false, = ["enabled"] }
Available Features
enabled- Core functionality (required)simd- SIMD optimizations for 4-25x parsing performanceenhanced_repl- Advanced REPL with history, completion, secure inputrepl- Basic REPL functionalityon_unknown_suggest- Fuzzy command suggestions
Examples and Learning Path
🚀 Start Here: Recommended Learning Path
1. Quick Start (Runtime, Educational Only)
00_quick_start.rs- Get something working in 5 minutes (⚠️ runtime registration, slow)01_basic_command_registration.rs- Understand the runtime API (⚠️ 50x slower than compile-time)
2. Production Approach (Compile-Time, Recommended)
static_01_basic_compile_time.rs- READ THIS FIRST - Explains proper YAML + build.rs patternstatic_02_yaml_build_integration.rs- Multi-YAML file aggregationstatic_03_performance_comparison.rs- Benchmark compile-time vs runtime (proves 50x speedup)static_04_multi_module_aggregation.rs- Organize commands across modules
3. Advanced Type System
02_argument_types.rs- String, Integer, Float, Boolean, Path, etc. (⚠️ requiresjson_parser)03_collection_types.rs- Lists, Maps with custom delimiters14_advanced_types_validation.rs- Complex validation rules (⚠️ requiresjson_parser)
4. Help & User Experience
06_help_system.rs- Comprehensive help system18_help_conventions_demo.rs- Three help access methods (?, ??, .help)
5. REPL Applications
12_repl_loop.rs- Basic REPL implementation15_interactive_repl_mode.rs- Interactive arguments + secure input (⚠️ requiresenhanced_repl)17_advanced_repl_features.rs- History, completion, recovery (⚠️ requiresenhanced_repl)
6. Complete Applications
full_cli_example.rs- Full-featured CLI with all concepts integratedpractical_cli_aggregation.rs- Real-world multi-tool aggregation (⚠️ requiresmulti_file)
⚠️ Feature Requirements Legend
- No marker = Works with default features
- ⚠️
json_parser= Requires JSON support feature - ⚠️
enhanced_repl= Requires advanced REPL features - ⚠️
multi_file= Requires multi-file aggregation (default includes this)
WebAssembly Support
unilang provides full WebAssembly compatibility for browser deployment:
&&
WASM Features:
- Complete framework functionality in browsers
- SIMD acceleration where supported
- Optimized bundle size (800KB-1.2MB compressed)
- Seamless Rust-to-JavaScript integration
Migration from Runtime to Compile-Time
Migrate from runtime registration (slow) to compile-time registration (50x faster) in 4 steps.
Step 1: Extract Command Definitions to YAML
Before (Runtime, in main.rs):
let mut registry = new;
let greet_cmd = CommandDefinition ;
registry.command_add_runtime?;
After (Compile-Time, in unilang.commands.yaml):
- name: ".greet"
namespace: ""
description: "Greeting command"
hint: "Say hello"
status: "stable"
version: "1.0.0"
tags:
aliases:
permissions:
idempotent: true
deprecation_message: ""
http_method_hint: ""
auto_help_enabled: false
examples:
arguments:
- name: "name"
kind: "String"
description: "Person's name"
hint: "Name"
attributes:
optional: true
default: "World"
multiple: false
interactive: false
sensitive: false
validation_rules:
aliases:
tags:
routine_link: null
Step 2: Update Cargo.toml
Add feature flag:
[]
# Enable single-file YAML compile-time approach
= { = "0.28", = ["approach_yaml_single_build"] }
# Or use default (multi-file auto-discovery)
= "0.28"
Step 3: Configure Build Script (Single-File Only)
For approach_yaml_single_build, create build.rs:
Note: With default approach_yaml_multi_build, no build.rs needed - auto-discovery handles everything!
Step 4: Update Code to Use Static Registry
Before (Runtime):
use *;
After (Compile-Time):
use *;
// Include compile-time generated commands (auto-generated by build system)
include!;
Step 5: Measure Performance Improvement
Run benchmarks:
Expected results:
- Runtime registration: ~4,000ns per command lookup
- Compile-time registration: ~80-100ns per command lookup
- Performance gain: 50x faster
Performance Optimization Guidelines
Compile-Time Best Practices
- Use static command definitions for all known commands
- Leverage multi-module aggregation for organization
- Enable SIMD features for maximum parsing performance
- Utilize conflict detection during build process
Runtime Considerations
- Reserve runtime registration for truly dynamic scenarios
- Minimize command modifications during execution
- Use batch processing for multiple commands
- Implement proper error handling and recovery