Crate unilang

Crate unilang 

Source
Expand description

§Module :: unilang

experimental rust-status docs.rs Open in Gitpod discord

Zero-overhead command framework with compile-time command registration

§Table of Contents

Getting Started

Understanding Performance

Core Concepts

Advanced Topics

Reference


§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)

  1. Add dependency:

    [dependencies]
    unilang = "0.35"
  2. Create unilang.commands.yaml in project root:

    - name: ".greet"
      description: "Greeting command"
      arguments:
        - name: "name"
          kind: "String"
          attributes:
            optional: true
            default: "World"
  3. Run example:

    cargo run --example static_01_basic_compile_time

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
[dependencies]
unilang = "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 = CommandRegistry::new();

// ✅ Correct - using static registry
let registry = StaticCommandRegistry::from_commands(&STATIC_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?

  1. Check examples: Run cargo run --example static_01_basic_compile_time
  2. Enable verbose logging: Set RUST_LOG=debug
  3. Verify feature flags: Run cargo tree -f "{p} {f}"
  4. 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

§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" with namespace: "" - shows exact command users will type
  • Alternative: name: "greet" with namespace: ".session" - requires understanding concatenation
  • Always include the dot prefix in either name or namespace

§Step 2: Configure Cargo.toml

The default configuration already enables build-time YAML processing:

[dependencies]
# Multi-YAML build-time approach is enabled by default
unilang = "0.35"

For single-file YAML approach, use:

[dependencies]
unilang = { version = "0.35", default-features = false, features = [
  "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):

fn main()
{
  // Rebuild if YAML file changes
  println!( "cargo:rerun-if-changed=unilang.commands.yaml" );
  // Static registry generation happens automatically
}

Default Multi-YAML: No build.rs needed - automatic discovery of all .yaml files!

§Step 4: Zero-Cost Execution

use unilang::prelude::*;

// Include compile-time generated commands (created automatically by build system)
include!( concat!( env!( "OUT_DIR" ), "/static_commands.rs" ) );

fn main() -> Result< (), unilang::Error >
{
  // StaticCommandRegistry requires approach_yaml_single_build,
  // approach_yaml_multi_build, or other build-time approach feature
  let registry = StaticCommandRegistry::from_commands( &STATIC_COMMANDS );
  let pipeline = Pipeline::new( registry );

  // O(1) lookup - no hashing overhead
  let result = pipeline.process_command_simple( ".greet name::Alice" );

  println!( "Output: {}", result.outputs[ 0 ].content );
  Ok( () )
}

§Performance Comparison

ApproachLookup TimeMemory OverheadBinary Size
Build-Time (Static)~80nsZeroSmaller
Runtime (HashMap)~4,000nsHash tables + allocationsLarger

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:

cargo run --release --example static_03_performance_comparison

See /examples/static_03_performance_comparison.rs for full benchmark implementation.

§Comparison to Alternatives

How unilang differs from popular Rust CLI frameworks:

Featureunilangclapstructoptargh
Command LookupO(1) staticRuntime HashMapRuntimeRuntime
Definition StyleYAML/JSON/Rust DSLRust builder APIDerive macrosDerive macros
Modality SupportCLI, REPL, Web APICLI onlyCLI onlyCLI only
Multi-file OrganizationAuto-discoveryManualManualManual
Runtime RegistrationHybrid (10-50x slower†)NoNoNo
Build-time ValidationYesNoYes (compile)Yes (compile)
REPL SupportBuilt-inManualManualManual
Help GenerationAuto + 3 operatorsAutoAutoAuto
Performance~80ns lookup~200-500ns~200-500ns~100-300ns
CLI AggregationBuilt-inManualManualManual
Learning CurveMediumLowLowVery 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 (clap has most)
  • ❌ You want minimal learning curve (argh is 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):

#ApproachFeature FlagDefaultLookup SpeedWhen to Use
1YAML file → Build-time staticapproach_yaml_single_build~80nsSingle-file projects, compile-time validation
2Multi-YAML files → Build-time staticapproach_yaml_multi_build✅ DEFAULT~80nsModular projects, best DX, auto-discovery
3YAML file → Runtime loadingapproach_yaml_runtime~4,200nsPlugin configs, runtime loading
4JSON file → Build-time staticapproach_json_single_build~80nsJSON-first projects, API generation
5Multi-JSON files → Build-time staticapproach_json_multi_build~80nsLarge JSON projects, modular organization
6JSON file → Runtime loadingapproach_json_runtime~4,200nsRuntime config loading, dynamic commands
7Rust DSL (builder API)(always available)~4,200nsCore API, prototyping, type-safe definitions
8Rust DSL (const fn + static)approach_rust_dsl_const~80nsHigh-performance DSL, compile-time
18Hybrid (static + runtime)approach_hybridMixedBase 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( &std::env::args().collect() );

// REPL/interactive applications: String-based parsing
let result = pipeline.process_command_simple( ".greet name::Alice" );

§Decision 3: What Are the Naming Rules?

Commands should start with a dot:

.greet name::Alice           # Recommended
greet name::Alice            # Not recommended

§Decision 4: What Features Should I Enable?

Choose Your Configuration:

Use CaseConfigurationWhat You Get
Production (Recommended)unilang = "0.35"Multi-YAML + SIMD + Enhanced REPL
Custom Approachunilang = { 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:

.command ?                   # Traditional operator (bypasses validation)
.command ??                  # Modern parameter
.command.help                # Auto-generated help command

§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_repl feature 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 unilang::multi_yaml::CliBuilder;

// Aggregate multiple CLI tools into one unified command
let unified_cli = CliBuilder::new()
  .static_module_with_prefix( "database", "db", database_commands )
  .static_module_with_prefix( "filesystem", "fs", file_commands )
  .static_module_with_prefix( "network", "net", network_commands )
  .static_module_with_prefix( "build", "build", build_commands )
  .detect_conflicts( true )
  .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
db-cli migrate --direction up
file-cli copy --src ./source --dest ./target --recursive
net-cli ping google.com --count 10
build-cli compile --target release

After Aggregation:

# Single unified tool with consistent interface
unified-cli .db.migrate direction::up
unified-cli .fs.copy source::./source destination::./target recursive::true
unified-cli .net.ping host::google.com count::10
unified-cli .build.compile target::release

§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 = CliBuilder::new()
  .static_module_with_prefix( "tools", "tool", cli_a_commands )
  .static_module_with_prefix( "utils", "tool", cli_b_commands )  // Conflict!
  .detect_conflicts( true )  // Catches duplicate prefixes at build time
  .build_static();
§Help System Integration
# All aggregated commands support unified help
unified-cli .db.migrate.help       # Detailed help for database migrations
unified-cli .fs.copy ??            # Interactive help during command construction
unified-cli .net.ping ?            # Traditional help operator

§Advanced Aggregation Patterns

§Conditional Module Loading
let registry = CliBuilder::new()
  .conditional_module( "docker", docker_commands, &[ "feature_docker" ] )
  .conditional_module( "k8s", kubernetes_commands, &[ "feature_k8s" ] )
  .build_static();

// Only includes modules when features are enabled
§Multi-Source Aggregation
use std::path::PathBuf;

// Combine static commands (in-memory) and dynamic YAML loading
let registry = CliBuilder::new()
  .static_module_with_prefix( "core", ".core", core_commands )
  .dynamic_module_with_prefix( "plugins", PathBuf::from( "plugins.yaml" ), ".plugins" )
  .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

ApproachLookup TimeMemory OverheadConflict Detection
Build-TimeO(1) staticZeroBuild-time
RuntimeO(log n)Hash tablesRuntime

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
cargo run --example practical_cli_aggregation

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( ".namespace.command arg::value" );
if result.success
{
  println!( "Success: {}", result.outputs[ 0 ].content );
}

§Batch Processing

let commands = vec!
[
  ".file.create name::test.txt",
  ".file.write name::test.txt content::data",
  ".file.list pattern::*.txt",
];

let batch_result = pipeline.process_batch( &commands, ExecutionContext::default() );
println!( "Success rate: {:.1}%", batch_result.success_rate() * 100.0 );

§Error Handling

match pipeline.process_command_simple( ".command arg::value" )
{
  result if result.success =>
  {
    // Process successful execution
    for output in result.outputs
    {
      println!( "Output: {}", output.content );
    }
  }
  result =>
  {
    if let Some( error ) = result.error
    {
      eprintln!( "Command failed: {}", error );
    }
  }
}

§Help System

unilang provides comprehensive help with three access methods:

§Traditional Help Operator

.command ?                    # Instant help, bypasses validation

§Modern Help Parameter

.command ??                   # Clean help access
.command arg1::value ??       # Help with partial arguments

§Auto-Generated Help Commands

.command.help                 # Direct help command access
.namespace.command.help       # Works with namespaced commands

§Feature Configuration

§Core Features

[dependencies]
unilang = "0.10"              # Default: enhanced_repl + simd + enabled

§Performance Optimized

[dependencies]
unilang = { version = "0.10", features = ["simd", "enhanced_repl"] }

§Minimal Footprint

[dependencies]
unilang = { version = "0.10", default-features = false, features = ["enabled"] }

§Available Features

  • enabled - Core functionality (required)
  • simd - SIMD optimizations for 4-25x parsing performance
  • enhanced_repl - Advanced REPL with history, completion, secure input
  • repl - Basic REPL functionality
  • on_unknown_suggest - Fuzzy command suggestions

§Examples and 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 pattern
  • static_02_yaml_build_integration.rs - Multi-YAML file aggregation
  • static_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. (⚠️ requires json_parser)
  • 03_collection_types.rs - Lists, Maps with custom delimiters
  • 14_advanced_types_validation.rs - Complex validation rules (⚠️ requires json_parser)

4. Help & User Experience

  • 06_help_system.rs - Comprehensive help system
  • 18_help_conventions_demo.rs - Three help access methods (?, ??, .help)

5. REPL Applications

  • 12_repl_loop.rs - Basic REPL implementation
  • 15_interactive_repl_mode.rs - Interactive arguments + secure input (⚠️ requires enhanced_repl)
  • 17_advanced_repl_features.rs - History, completion, recovery (⚠️ requires enhanced_repl)

6. Complete Applications

  • full_cli_example.rs - Full-featured CLI with all concepts integrated
  • practical_cli_aggregation.rs - Real-world multi-tool aggregation (⚠️ requires multi_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:

cd examples/wasm-repl
wasm-pack build --target web --release
cd www && python3 -m http.server 8000

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 = CommandRegistry::new();

let greet_cmd = CommandDefinition {
  name: ".greet".to_string(),
  namespace: String::new(),
  description: "Greeting command".to_string(),
  hint: "Say hello".to_string(),
  arguments: vec![
    ArgumentDefinition {
      name: "name".to_string(),
      kind: Kind::String,
      description: "Person's name".to_string(),
      hint: "Name".to_string(),
      attributes: ArgumentAttributes {
        optional: true,
        default: Some("World".to_string()),
        ..Default::default()
      },
      validation_rules: vec![],
      aliases: vec![],
      tags: vec![],
    }
  ],
  // ... other fields
  status: "stable".to_string(),
  version: "1.0.0".to_string(),
  aliases: vec![],
  tags: vec![],
  permissions: vec![],
  idempotent: true,
  deprecation_message: String::new(),
  http_method_hint: String::new(),
  examples: vec![],
  routine_link: None,
  auto_help_enabled: false,
};

registry.command_add_runtime(&greet_cmd, greet_routine)?;

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:

[dependencies]
# Enable single-file YAML compile-time approach
unilang = { version = "0.35", features = ["approach_yaml_single_build"] }

# Or use default (multi-file auto-discovery)
unilang = "0.35"

§Step 3: Configure Build Script (Single-File Only)

For approach_yaml_single_build, create build.rs:

fn main()
{
  // Rebuild if YAML file changes
  println!("cargo:rerun-if-changed=unilang.commands.yaml");

  // Static registry generation happens automatically
  // No manual code needed - the feature flag handles it
}

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 unilang::prelude::*;

fn main() -> Result<(), unilang::Error> {
  let mut registry = CommandRegistry::new();

  // Manual registration (10-50x slower than static)
  registry.command_add_runtime(&greet_cmd, greet_routine)?;

  let pipeline = Pipeline::new(registry);
  let result = pipeline.process_command_simple(".greet name::Alice");
  Ok(())
}

After (Build-Time):

use unilang::prelude::*;

// Include build-time generated commands (auto-generated by build system)
include!(concat!(env!("OUT_DIR"), "/static_commands.rs"));

fn main() -> Result<(), unilang::Error> {
  // Zero-cost static registry (~80ns lookup vs ~4,000ns runtime)
  let registry = StaticCommandRegistry::from_commands(&STATIC_COMMANDS);

  let pipeline = Pipeline::new(registry);
  let result = pipeline.process_command_simple(".greet name::Alice");
  Ok(())
}

§Step 5: Measure Performance Improvement

Run benchmarks:

cargo run --example static_03_performance_comparison

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

§Design Rules Compliance Notice

CRITICAL: This codebase must follow strict design rules. Before making changes, review:

  • $PRO/genai/code/rules/code_design.rulebook.md - Core design patterns and architecture rules
  • $PRO/genai/code/rules/code_style.rulebook.md - Code formatting and style requirements

Key Rules Summary:

  • Testing: All tests MUST be in tests/ directory, NOT in src/ as mod tests
  • Benchmarking: Use benchkit framework ONLY - no custom timing code in tests
  • Performance Tests: NEVER mix benchmarks with unit tests - separate concerns
  • Test Documentation: Every test file MUST have Test Matrix documentation
  • Directory Structure: tests/ for tests, benches/ for benchmarks (if using benchkit)

Common Violations to Avoid: ❌ Custom std::time::Instant timing code in test files ❌ Performance/benchmark tests in tests/ directory ❌ Missing file-level documentation with Test Matrix in test files ❌ Using anything other than benchkit for performance measurement

§Feature Flags

Unilang supports multiple feature flags to customize functionality and dependencies:

§Core Features

  • enabled - Core functionality (included in default)
  • full - All features enabled for maximum functionality

§REPL Features

  • repl - Basic REPL functionality with standard I/O

    • Provides interactive command execution
    • Basic command history tracking
    • Cross-platform compatibility
    • No additional dependencies
  • enhanced_replEnabled by Default - Advanced REPL with rustyline integration

    • Enables: All features from repl plus:
    • Arrow Key Navigation: ↑/↓ for command history browsing
    • Tab Auto-completion: Command and argument completion
    • Interactive Prompts: Secure password input with masking
    • Session Persistence: History saved across sessions
    • Terminal Detection: Auto-fallback to basic REPL in non-interactive environments
    • Dependencies: rustyline, std::io::IsTerminal

§Performance Features

  • simd - SIMD optimizations for parsing and JSON processing
    • Enables: simd-json (4-25x faster JSON), SIMD string operations
    • Automatic: Included in default for maximum performance
    • Disable with: cargo build --no-default-features --features enabled

§Optional Features

  • on_unknown_suggest - Fuzzy command suggestions (requires textdistance)

Note: Benchmarking tools are available in the separate unilang_benchmarks workspace crate

§Usage Examples

Basic REPL (minimal dependencies):

[dependencies]
unilang = { version = "0.10", features = ["repl"] }

Default (Enhanced REPL included):

[dependencies]
unilang = "0.10"  # Enhanced REPL enabled by default

Performance-optimized CLI:

[dependencies]
unilang = { version = "0.10", features = ["enhanced_repl", "simd", "on_unknown_suggest"] }

Embedded/minimal:

[dependencies]
unilang = { version = "0.10", default-features = false, features = ["enabled"] }

§Feature Compatibility

  • enhanced_repl automatically includes repl
  • full includes all features except development-only ones
  • All features work together without conflicts
  • Enhanced REPL gracefully falls back to basic REPL when needed

Re-exports§

pub use super::private::TypeAnalyzer;
pub use super::private::TypeHint;
pub use super::private::Severity;
pub use super::private::HintGenerator;
pub use super::aggregator;
pub use super::builder;
pub use super::type_analyzer;
pub use super::hint_generator;
pub use super::private::TypeAnalyzer;
pub use super::private::TypeHint;
pub use super::private::Severity;
pub use super::private::HintGenerator;
pub use unilang_parser as parser;
pub use super::prelude::*;
pub use super::prelude::*;

Modules§

build_helpers
Build-time helper utilities for type analysis and hint generation. Provides tools for detecting type issues in YAML command definitions during build. Requires feature: yaml_parser Build-time helper utilities for static registry generation
command_validation
Command validation utilities. Command registration validation and utilities.
config_extraction
Config value extraction utilities. Generic extractors for HashMap<String, (JsonValue, S)> config maps. Requires feature: json_parser
data
Core data structures and types.
error
Error handling utilities.
exposed
Exposed namespace of the module.
help
Help generation system.
interner
String interning system for performance optimization. String Interning System
interpreter
Command execution interpreter.
loader
Configuration loading from YAML/JSON. Functions gated by yaml_parser and json_parser features.
multi_yaml
Multi-YAML build system for compile-time aggregation. Requires feature: multi_file Multi-YAML Build System and Ergonomic Aggregation APIs
orphan
Orphan namespace of the module.
own
Own namespace of the module.
pipeline
High-level pipeline API.
prelude
Prelude to use essentials: use my_module ::prelude :: *.
registry
Command registry management. Some functions gated by approach features.
semantic
Semantic analysis and validation.
simd_json_parser
SIMD-optimized JSON parsing for 4-25x performance improvements. Requires features: simd-json AND json_parser
simd_tokenizer
SIMD-optimized tokenization for 3-6x performance improvements. SIMD-optimized tokenization for high-performance string processing.
static_data
Static data structures for compile-time commands. Requires feature: static_registry
types
Value types and type system.
validation_core
Core validation logic shared between runtime and build.rs. This module can be included in build.rs via include!() since it has no dependencies. Core validation logic shared between runtime and build.rs.

Structs§

AggregationConfig
Re-export key aggregator types Re-export key aggregator types Configuration for multi-YAML aggregation
ArgumentAttributes
Holds attributes and configuration for a specific argument within a command.
ArgumentDefinition
Defines an argument within a command, including its name, type, and constraints.
BatchResult
Result of processing multiple commands through the pipeline.
CliBuilder
Re-export key builder types Re-export key builder types Ergonomic CLI builder for simple and complex aggregation scenarios
CliConfig
Re-export key builder types Re-export key builder types Global CLI configuration
CommandDefinition
Type-safe command definition with validated newtypes and private fields.
CommandDefinitionBuilder
Type-state builder for CommandDefinition that enforces required fields at compile time.
CommandName
A validated command name that guarantees the dot prefix convention.
CommandRegistry
Runtime command registration. Consider compile-time alternatives for better performance. Runtime command registration. Consider compile-time alternatives for better performance. Runtime command registration. Consider compile-time alternatives for better performance.
CommandRegistryBuilder
A builder for constructing CommandRegistry instances with a fluent API.
CommandResult
Result of processing a single command through the pipeline.
ConditionalModule
Re-export key builder types Re-export key builder types Conditional module based on feature flags
ConflictReport
Re-export key aggregator types Re-export key aggregator types Report of detected conflicts
DynamicCommandMap
Optimized dynamic command storage with intelligent caching
DynamicModule
Re-export key builder types Re-export key builder types Dynamic YAML module configuration for ergonomic APIs
EnvConfigParser
Re-export key aggregator types Re-export key aggregator types Environment variable configuration parser
ErrorData
Represents an error that occurred during command execution
ExecutionContext
The execution context for a command.
FastJsonValue
Performance-optimized JSON value for applications that need maximum parsing speed with minimal allocations.
HelpDisplayOptions
Global configuration for help output display.
HelpGenerator
Generates help information for commands.
InternerStats
Statistics about the string interner’s current state.
Interpreter
The interpreter for Unilang commands.
ModuleConfig
Re-export key aggregator types Re-export key aggregator types Configuration for a single module
MultiYamlAggregator
Re-export key aggregator types Re-export key aggregator types Multi-YAML aggregation system for compile-time command processing
Namespace
Represents a namespace within the command system.
NamespaceIsolation
Re-export key aggregator types Re-export key aggregator types Namespace isolation configuration
NamespaceType
A validated namespace that guarantees correct naming conventions.
NotSet
Marker type indicating a required field has not been set.
OutputData
Represents the output of a successfully executed command.
PerformanceMetrics
Performance metrics for command registry operations.
Pipeline
A high-level pipeline processor that combines parsing, semantic analysis, and execution.
SIMDJsonParser
High-performance JSON parser using SIMD optimizations.
SIMDTokenizer
SIMD-optimized tokenizer for splitting strings by delimiters. SIMD-optimized tokenizer for splitting strings by delimiters.
SemanticAnalyzer
The semantic analyzer, responsible for validating the parsed program.
Set
Marker type indicating a required field has been set.
StaticArgumentAttributes
Static, const-compatible version of ArgumentAttributes.
StaticArgumentDefinition
Static, const-compatible version of ArgumentDefinition.
StaticCommandDefinition
Static, const-compatible version of CommandDefinition.
StaticCommandMap
Wrapper for static command maps with zero-overhead compile-time lookup.
StaticCommandRegistry
High-performance static command registry with zero-cost compile-time lookup. High-performance static command registry with zero-cost compile-time lookup. High-performance static command registry with zero-cost compile-time lookup.
StaticModule
Re-export key builder types Re-export key builder types Static module configuration for ergonomic APIs
StringInterner
Thread-safe string interner that caches strings and returns ’static references.
TypeError
An error that can occur during type parsing or validation.
VerifiedCommand
Represents a command that has been verified against the command registry.
VersionType
A validated version string.

Enums§

AggregationMode
Re-export key builder types Re-export key builder types Ergonomic CLI aggregation modes
CommandStatus
Command status indicating lifecycle stage and availability.
ConflictResolutionStrategy
Re-export key aggregator types Re-export key aggregator types Conflict resolution strategies for handling duplicate commands
ConflictType
Re-export key aggregator types Re-export key aggregator types Types of conflicts that can be detected
Error
The main error type for the Unilang framework.
ErrorCode
Standard error codes for command execution failures
HelpVerbosity
Help verbosity levels controlling output detail.
Kind
Represents the data type and structure of an argument or value.
ModuleSource
Re-export key builder types Re-export key builder types Module source type for aggregation
RegistryMode
Registry operation mode for hybrid command lookup optimization
StaticKind
Static, const-compatible version of Kind.
StaticValidationRule
Static, const-compatible version of ValidationRule.
UnilangError
Structured error types for better API consistency and error handling.
ValidationRule
Validation rule for argument values.
Value
Represents a parsed and validated value of a specific kind.

Traits§

CommandRegistryTrait
Common trait for command registries to enable interoperability.

Functions§

aggregate_cli_complex
Re-export key aggregator types Re-export key aggregator types More complex aggregate_cli simulation
aggregate_cli_simple
Re-export key aggregator types Re-export key aggregator types Convenience function for zero-boilerplate static aggregation (aggregate_cli! macro simulation)
compute_full_name_core
Computes full command name from namespace and name.
create_aggregated_registry
Re-export key aggregator types Re-export key aggregator types Runtime multi-YAML aggregation with environment variable support.
extract_bool
Extract bool value from config.
extract_f64
Extract f64 value from config.
extract_i32
Extract i32 value from config.
extract_i64
Extract i64 value from config.
extract_string
Extract String value from config.
extract_string_array
Extract array of strings from config.
extract_u8
Extract u8 value from config.
extract_u16
Extract u16 value from config.
extract_u32
Extract u32 value from config.
extract_u64
Extract u64 value from config.
global_interner
Returns a reference to the global string interner instance.
intern
Convenience function to intern a string using the global interner.
intern_command_name
Convenience function to intern command names using the global interner.
is_help_command
Checks if command name ends with “.help” suffix.
is_simd_enabled
Returns true if SIMD optimizations are available and enabled. Returns true if SIMD optimizations are available and enabled.
load_command_definitions_from_json_str
Loads command definitions from a JSON string.
load_command_definitions_from_yaml_str
Loads command definitions from a YAML string.
make_help_command_name
Builds help command name from command name.
parse_cargo_metadata
Re-export key aggregator types Re-export key aggregator types Parse Cargo.toml metadata for build configuration
parse_value
Parses a raw string input into a Value based on the specified Kind.
process_single_command
Convenience function to process a single command with a registry.
resolve_routine_link
Resolves a routine link string to a CommandRoutine.
simd_support_info
CPU feature detection for SIMD optimization selection. CPU feature detection for SIMD optimization selection.
validate_command_definition_core
Validates a complete command definition at build time.
validate_command_for_registration
Validates entire command definition for registration.
validate_command_name
Validates command name follows dot-prefix naming convention.
validate_command_name_core
Validates command name follows dot-prefix naming convention.
validate_full_name_core
Validates the full name (namespace + name combination).
validate_namespace
Validates namespace follows dot-prefix naming convention.
validate_namespace_core
Validates namespace follows dot-prefix naming convention.
validate_parameter_storage_types
Validates parameter storage types match their multiple attribute.
validate_single_command
Convenience function to validate a single command with a registry.
validate_version_core
Validates version string is non-empty.

Type Aliases§

CommandRoutine
Type alias for a command routine. A routine takes a VerifiedCommand and an ExecutionContext, and returns a Result of OutputData or ErrorData.
ConfigMap
Type alias for configuration maps with any source type.