Module :: unilang
Zero-overhead command framework with compile-time command registration
Value Proposition
unilang processes command definitions at compile-time, generating optimized static command maps (using Perfect Hash Functions internally) that provide O(1) command lookups with zero runtime overhead and zero additional dependencies for downstream crates. This approach delivers:
- 10-50x faster command resolution compared to runtime HashMap lookups
- 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 Build Script
Add to build.rs:
use env;
use Path;
Step 3: Zero-Cost Execution
use *;
// Include compile-time generated commands
include!;
Performance Comparison
| Approach | Lookup Time | Memory Overhead | Binary Size |
|---|---|---|---|
| Compile-Time (Static) | 1-3 CPU cycles | Zero | Smaller |
| Runtime (HashMap) | 50-150 CPU cycles | Hash tables + allocations | Larger |
Benchmark Results:
- Static lookups: ~2ns per operation
- Dynamic lookups: ~80ns per operation
- Performance gain: 40x faster command resolution
User Guide: Integration Decisions
Decision 1: How Should I Define Commands?
10 approaches are currently implemented (see full comparison):
| # | Approach | Lookup Speed | When to Use |
|---|---|---|---|
| 1 | YAML file → Build-time static ⭐ | ~80ns | Production apps, best performance, compile-time validation |
| 2 | Multi-YAML files → Build-time static | ~80ns | Large modular projects, multiple CLI tools unified |
| 3 | YAML file → Runtime loading | ~4,200ns | Development, plugin configs loaded at runtime |
| 4 | JSON file → Build-time static | ~80ns | JSON-first projects, API-driven CLI generation |
| 5 | Multi-JSON files → Build-time static | ~80ns | Large JSON projects, modular organization |
| 6 | JSON file → Runtime loading | ~4,200ns | Runtime config loading, dynamic commands |
| 7 | Rust DSL (inline closures) | ~4,200ns | ⚠️ Prototyping/testing only, NOT for production |
| 8 | Rust DSL (const fn + static) | ~80ns | High-performance DSL, type-safe compile-time definitions |
| 18 | Hybrid (static + runtime) | Mixed | Base CLI + plugin system (best of both worlds) |
Strongly Recommended: Row 1 (YAML + build-time static) for 50x better performance and compile-time validation.
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 (SIMD enabled automatically)
[]
= "0.26" # Includes SIMD (4-25x parsing speedup), enhanced REPL
Minimal build:
= { = "0.26", = false, = ["enabled"] }
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
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
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
// - dynamic_module_with_prefix(name, PathBuf, prefix)
// → Commands loaded from YAML file at runtime, ~50x slower lookup
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: ~750ns lookup regardless of module count
- Single static map: All 1,000 commands accessible in constant time
- 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
Compile-Time Focus Examples
static_01_basic_compile_time.rs- Zero-cost static lookupsstatic_02_yaml_build_integration.rs- Build script integration patternsstatic_03_performance_comparison.rs- Concrete performance measurementsstatic_04_multi_module_aggregation.rs- Modular command organization
Traditional Examples
01_basic_command_registration.rs- Runtime registration patterns02_argument_types.rs- Comprehensive argument type examples07_yaml_json_loading.rs- Dynamic command loading
Advanced Features
18_help_conventions_demo.rs- Help system demonstrationfull_cli_example.rs- Complete CLI application
REPL and Interactive
12_repl_loop.rs- Basic REPL implementation15_interactive_repl_mode.rs- Interactive arguments and secure input17_advanced_repl_features.rs- History, auto-completion, error recovery
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
Step 1: Extract Command Definitions
Convert runtime CommandDefinition structures to YAML format.
Step 2: Configure Build Script
Add compile-time generation to build.rs.
Step 3: Update Code
Replace CommandRegistry::new() with compile-time command registration via build.rs.
Step 4: Measure Performance
Use provided benchmarking examples to verify improvements.
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