Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
Module :: unilang
Zero-overhead command framework with compile-time command registration
Table of Contents
Getting Started
- Value Proposition - Why unilang?
- Architecture Overview - How it works
- Getting Started (60 Seconds) - Quick start
- Troubleshooting - Common issues & solutions
- Quick Start: Build-Time Registration - Detailed guide
Understanding Performance
- Performance Comparison - Benchmarks & methodology
- Comparison to Alternatives - vs clap/structopt/argh
Core Concepts
- User Guide: Integration Decisions - Design choices
- Command Definition Format - YAML structure
- Command Execution Patterns - Usage patterns
- Help System - Three access methods
Advanced Topics
- CLI Aggregation - Multi-tool consolidation
- Migration from Runtime to Build-Time - Upgrade guide
- Performance Optimization Guidelines - Tuning
- WebAssembly Support - Browser deployment
Reference
- Usage Guide (usage.md) - Complete syntax reference
- Feature Configuration - Feature flags
- Examples and Learning Path - Code examples
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
Build-Time Processing (Happens Once)
Developer writes YAML
|
v
unilang.commands.yaml
- name: ".greet"
description: "..."
arguments: [...]
|
v
build.rs (automatic)
- Discovers YAML files
- Validates definitions
- Generates static command map
|
v
OUT_DIR/static_commands.rs
static STATIC_COMMANDS: [...]
// Static commands with O(1) lookups
|
v
Binary compiled
(zero-overhead ready)
Runtime Execution (Every Command)
User: ".greet name::Alice"
|
v
Parser
(SIMD accelerated)
|
v
Static Registry Lookup
O(1) static map access
~80ns (no hashing!)
|
v
Semantic Analyzer
- Validate types
- Apply defaults
- Check constraints
|
v
Command Routine
Execute business logic
|
v
Output Result
Key Benefits:
- ⚡ Build-time: Validation catches errors before deployment
- 🚀 Runtime: O(1) lookups with zero allocations (~80ns)
- 📦 Binary: Smaller size via static analysis
- 🔒 Type-safe: Impossible to register invalid commands
Getting Started (60 Seconds)
-
Add dependency:
[] = "0.35" -
Create
unilang.commands.yamlin project root:- name: ".greet" description: "Greeting command" arguments: - name: "name" kind: "String" attributes: optional: true default: "World" -
Run example:
What just happened? Commands auto-discovered from YAML, compiled into zero-overhead static registry, ready for O(1) lookups.
Next: See detailed guide for production setup.
Troubleshooting
Common issues and solutions for new users:
❌ "Command not found" error
Symptom: Error: Command '.greet' not found in registry
Cause: Command name missing dot prefix
Solution:
# ❌ Wrong
- name: "greet"
# ✅ Correct
- name: ".greet"
All command names MUST start with . (dot prefix)
❌ "Type mismatch" error during build
Symptom: Type hint warnings during cargo build
Cause: YAML default values quoted when they shouldn't be
Solution:
# ❌ Wrong - quoted values
arguments:
- name: "dry"
kind: "Boolean"
attributes:
default: 'false' # String, not Boolean!
# ✅ Correct - unquoted primitives
arguments:
- name: "dry"
kind: "Boolean"
attributes:
default: false # Boolean type
Rule: Boolean, Integer, Float values must NOT be quoted in YAML
❌ Build fails with "could not find static_commands.rs"
Symptom: error: couldn't read .../static_commands.rs: No such file or directory
Cause: Wrong feature flag or missing build-time approach
Solution:
# Ensure you have a build-time approach enabled
[]
= "0.35" # Default includes approach_yaml_multi_build
Check that you have at least one .yaml file with commands, or enable a different build-time approach feature.
❌ Performance not improved after migration
Symptom: Lookups still slow after switching to build-time approach
Cause: Using runtime registration in production CLI (10-50x performance penalty)
Solution:
// ❌ Wrong for production CLIs - 10-50x slower than static registration
// ✅ Appropriate for REPL/plugins/prototyping where flexibility > performance
let registry = new;
// ✅ Correct - using static registry
let registry = from_commands;
Verify you're using StaticCommandRegistry, not CommandRegistry::new().
❌ "Unknown parameter" error
Symptom: Error: Unknown parameter 'nam'
Cause: Typo in parameter name
Solution: Check error message for "Did you mean...?" suggestion:
Error: Unknown parameter 'nam'. Did you mean 'name'?
Use '.greet ??' for help
Parameter names are validated strictly - use ?? operator to see valid parameters.
🔍 Still having issues?
- Check examples: Run
cargo run --example static_01_basic_compile_time - Enable verbose logging: Set
RUST_LOG=debug - Verify feature flags: Run
cargo tree -f "{p} {f}" - Review usage.md for detailed syntax rules
Usage Guide
For comprehensive usage patterns, best practices, and quick reference: See usage.md for concise guide covering:
- Command naming conventions and structure
- Argument types and validation
- Parameter syntax and quoting rules
- Help system (3 access methods)
- Error handling patterns
- REPL implementation
- CLI aggregation
- Testing and performance
- Security considerations
Quick Start: Build-Time Registration (Recommended)
Step 1: Define Commands
Create unilang.commands.yaml:
- name: ".greet" # RECOMMENDED: Show full command name
namespace: "" # Leave empty for root-level commands
description: "High-performance greeting command"
arguments:
- name: "name"
kind: "String"
attributes:
optional: true
default: "World"
YAML Command Naming:
- Recommended:
name: ".greet"withnamespace: ""- shows exact command users will type - Alternative:
name: "greet"withnamespace: ".session"- requires understanding concatenation - Always include the dot prefix in either
nameornamespace
Step 2: Configure Cargo.toml
The default configuration already enables build-time YAML processing:
[]
# Multi-YAML build-time approach is enabled by default
= "0.35"
For single-file YAML approach, use:
[]
= { = "0.35", = false, = [
"enabled",
"approach_yaml_single_build" # Single YAML file at compile-time
]}
Step 3: Build Script (Do You Need build.rs?)
Decision Tree:
Using default multi-YAML approach?
├─ YES → ✅ No build.rs needed (auto-discovery)
└─ NO → Using single-file YAML?
├─ YES → ✅ Add minimal build.rs below
└─ NO → ✅ Custom approach - implement discovery logic
For Single-File YAML Only (approach_yaml_single_build):
Default Multi-YAML: No build.rs needed - automatic discovery of all .yaml files!
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 |
|---|---|---|---|
| Build-Time (Static) | ~80ns | Zero | Smaller |
| Runtime (HashMap) | ~4,000ns | Hash tables + allocations | Larger |
Benchmark Results:
- Static lookups: ~80-100ns (static map + zero allocations)
- Runtime lookups: ~4,000-5,000ns (HashMap + semantic analysis)
- Performance gain: 50x faster command resolution
Benchmark Methodology
Hardware: AMD Ryzen 9 5950X, 64GB RAM, NVMe SSD
Framework: benchkit - specialized benchmarking framework for unilang
Test Scenario: Lookup 100 commands from registry of 1,000 commands
Iterations: 10,000 runs per approach, median reported
Tool: cargo run --example static_03_performance_comparison
What's measured:
- Static: Static map lookup + CommandDefinition retrieval
- Runtime: HashMap lookup + CommandDefinition retrieval
- Excludes parsing (measured separately with SIMD benchmarks)
Run benchmarks yourself:
See /examples/static_03_performance_comparison.rs for full benchmark implementation.
Comparison to Alternatives
How unilang differs from popular Rust CLI frameworks:
| Feature | unilang | clap | structopt | argh |
|---|---|---|---|---|
| Command Lookup | O(1) static | Runtime HashMap | Runtime | Runtime |
| Definition Style | YAML/JSON/Rust DSL | Rust builder API | Derive macros | Derive macros |
| Modality Support | CLI, REPL, Web API | CLI only | CLI only | CLI only |
| Multi-file Organization | Auto-discovery | Manual | Manual | Manual |
| Runtime Registration | Hybrid (10-50x slower†) | No | No | No |
| Build-time Validation | Yes | No | Yes (compile) | Yes (compile) |
| REPL Support | Built-in | Manual | Manual | Manual |
| Help Generation | Auto + 3 operators | Auto | Auto | Auto |
| Performance | ~80ns lookup | ~200-500ns | ~200-500ns | ~100-300ns |
| CLI Aggregation | Built-in | Manual | Manual | Manual |
| Learning Curve | Medium | Low | Low | Very Low |
† Runtime registration appropriate for REPL applications, plugin systems, and prototyping. Not recommended for production CLIs due to performance penalty.
When to Choose unilang
Choose unilang if you need:
- ✅ REPL or interactive shell interfaces
- ✅ Multi-modality support (CLI + Web API + TUI)
- ✅ Runtime plugin/command discovery (hybrid mode)
- ✅ Maximum performance with static dispatch
- ✅ CLI aggregation across multiple crates
- ✅ Declarative YAML/JSON command definitions
Choose alternatives if:
- ❌ You only need basic CLI arg parsing (use
argh- simplest) - ❌ You prefer pure-Rust derive macros (use
structopt/clap) - ❌ You need mature ecosystem with extensive plugins (
claphas most) - ❌ You want minimal learning curve (
arghis fastest to learn)
Philosophy Differences
unilang:
- "Define once, use everywhere" - single command definition for all modalities
- Optimized for command-rich applications (100s of commands)
- Build-time optimization and validation
clap/structopt/argh:
- "CLI-first" - specialized for argument parsing
- Optimized for applications with 1-20 commands
- Runtime flexibility, simpler mental model
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?
Choose Your Configuration:
| Use Case | Configuration | What You Get |
|---|---|---|
| Production (Recommended) | unilang = "0.35" |
Multi-YAML + SIMD + Enhanced REPL |
| Custom Approach | unilang = { version = "0.35", default-features = false, features = ["enabled", "approach_json_single_build"] } |
Switch to specific approach |
| Minimal (Core API Only) | unilang = { version = "0.35", default-features = false, features = ["enabled"] } |
Rust DSL only, no build-time |
| Full (Development/Testing) | unilang = { version = "0.35", features = ["full"] } |
All 21 approaches available |
Most users: Just use unilang = "0.35" and you're done.
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
Advanced Topics
The following sections cover advanced usage patterns, migration strategies, and specialized deployments. New users should start with the Getting Started section above.
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 |
|---|---|---|---|
| Build-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
Common Pitfalls (Type Defaults)
⚠️ YAML permits type coercion, but unilang enforces strict typing. The build system now emits type hints for these common mistakes:
❌ WRONG - Quoted defaults for typed arguments:
- name: "dry"
kind: "Boolean"
attributes:
default: 'false' # String literal, not boolean
- name: "verbosity"
kind: "Integer"
attributes:
default: '2' # String literal, not integer
✅ CORRECT - Unquoted defaults matching argument type:
- name: "dry"
kind: "Boolean"
attributes:
default: false # Boolean value
- name: "verbosity"
kind: "Integer"
attributes:
default: 2 # Integer value
💡 Type Hint Detection: The build system analyzes argument definitions and emits non-blocking hints during cargo build when it detects potential type mismatches. To suppress hints for intentional cases (e.g., version strings like "1.0"), add suppress_type_hint: true to the argument's attributes.
Help Generation:
auto_help_enabled: true # Default: true. Controls auto-generation of .command.help
# Set to false to prevent .command.help creation
# Help still available via ? and ?? operators
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 suggestionsstatic_registry- Static command registry with PHF (Perfect Hash Functions)
PHF Re-export (Static Registry Feature)
When using the static_registry feature, unilang generates code that uses Perfect Hash Functions (PHF) for compile-time command lookup. To simplify dependency management, unilang re-exports PHF types publicly.
Usage
Enable the feature in Cargo.toml:
[]
= { = "0.46", = ["static_registry"] }
Use PHF types via unilang::phf:
// Import both the module (self) and types
use ;
// Use module-qualified macro calls
static COMMANDS: = phf_map! ;
Important: Import the phf module itself with self and use qualified macro calls (phf::phf_map!), not phf_map! directly. This ensures the macro's internal references resolve correctly.
Migration from Direct PHF Dependency
If you previously added phf as a direct dependency, follow these steps to migrate:
Step 1: Update Cargo.toml
Before (with direct PHF dependency):
[]
= { = "0.45", = ["static_registry"] }
= "0.11" # Direct dependency - REMOVE THIS
After (using unilang's re-export):
[]
= { = "0.46", = ["static_registry"] }
# No phf dependency needed - it's re-exported by unilang
Step 2: Update Import Statements
Before (direct import):
use ;
static MAP: = phf_map! ;
After (import from unilang):
use ; // Import module + types
static MAP: = phf_map! ; // Qualified macro call
Note: You must import the phf module itself (self) and use phf::phf_map! (not phf_map! directly).
Step 3: Verify Migration
# Remove unused dependency
# Should build successfully without direct phf dependency
Why Re-export?
- Simplified Dependencies: No need to add
phfto yourCargo.toml - Version Compatibility: Unilang manages PHF version, avoiding conflicts
- Zero Runtime Cost: PHF provides O(1) lookup at compile time
- Future-Proof: Unilang can update PHF version without breaking your code
Troubleshooting
Error: "unresolved import unilang::phf"
Cause: The static_registry feature is not enabled.
Solution: Add the feature to your dependency:
[]
= { = "0.46", = ["static_registry"] }
Error: "multiple candidates for Map"
Cause: You have both phf as a direct dependency and are using unilang::phf.
Solution: Remove the direct phf dependency from your Cargo.toml. Use unilang::phf::Map exclusively:
use Map; // Only import from unilang
// Remove: use phf::Map;
Warning: "unused dependency: phf"
Cause: You have phf in your Cargo.toml but are now using unilang::phf.
Solution: Remove the unused dependency:
# Edit Cargo.toml and remove the line: phf = "0.11"
Error: "error: cannot find macro phf_map in this scope"
Cause: You're trying to use phf_map! macro without importing it.
Solution: Import both the macro and types:
use ; // Import macro AND type
static MY_MAP: = phf_map! ;
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 build-time)
2. Production Approach (Build-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 Build-Time
⚠️ PERFORMANCE NOTICE: Runtime command registration (CommandRegistry::new() and command_add_runtime()) has 10-50x slower performance than compile-time registration.
When to use runtime registration:
- ✅ REPL applications - Commands defined interactively
- ✅ Plugin systems - Commands loaded dynamically at runtime
- ✅ Prototyping - Rapid development iteration
When to use compile-time registration:
- ⚡ Production CLIs - Performance-critical applications
- ⚡ Large command sets - 100+ commands benefit from ~80ns PHF lookups
- ⚡ Embedded systems - Zero-overhead static dispatch
This section helps migrate performance-critical code from runtime to compile-time registration for 50x speedup.
Migrate from runtime registration (10-50x slower) to build-time registration (⚡ 50x faster) in 4 steps when performance matters.
Step 1: Extract Command Definitions to YAML
Before (Runtime, in main.rs): ⚠️ NOT RECOMMENDED FOR PRODUCTION CLIs (10-50x slower)
let mut registry = new;
let greet_cmd = CommandDefinition ;
registry.command_add_runtime?;
After (Build-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.35", = ["approach_yaml_single_build"] }
# Or use default (multi-file auto-discovery)
= "0.35"
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): ⚠️ 10-50x SLOWER (not recommended for production)
use *;
After (Build-Time):
use *;
// Include build-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