| Crates.io | unilang |
| lib.rs | unilang |
| version | 0.15.0 |
| created_at | 2025-05-11 00:58:51.602444+00 |
| updated_at | 2025-09-23 09:58:56.637942+00 |
| description | Define your command-line utility interface once and get consistent interaction across multiple modalities — CLI, GUI, TUI, AUI, Web APIs, and more—essentially for free. |
| homepage | https://github.com/Wandalen/wTools/tree/master/module/move/unilang/readme.md |
| repository | https://github.com/Wandalen/wTools/tree/master/module/move/unilang |
| max_upload_size | |
| id | 1668977 |
| size | 2,401,819 |
Zero-overhead command framework with compile-time command registration
unilang processes command definitions at compile-time, generating Perfect Hash Function (PHF) maps that provide O(1) command lookups with zero runtime overhead. This approach delivers:
Compile-Time Processing:
YAML definitions → build.rs → PHF maps → Zero-cost lookups
Runtime Execution:
Command string → O(1) PHF lookup → Validated execution
Create unilang.commands.yaml:
- name: "greet"
namespace: ""
description: "High-performance greeting command"
arguments:
- name: "name"
kind: "String"
attributes:
optional: true
default: "World"
Add to build.rs:
use std::env;
use std::path::Path;
fn main()
{
println!( "cargo:rerun-if-changed=unilang.commands.yaml" );
let out_dir = env::var( "OUT_DIR" ).unwrap();
let dest_path = Path::new( &out_dir ).join( "static_commands.rs" );
// Generate PHF maps at compile-time
unilang::build::generate_static_commands( &dest_path, "unilang.commands.yaml" );
}
use unilang::prelude::*;
// Include compile-time generated PHF maps
include!( concat!( env!( "OUT_DIR" ), "/static_commands.rs" ) );
fn main() -> Result< (), unilang::Error >
{
let registry = StaticCommandRegistry::new( &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( () )
}
| Approach | Lookup Time | Memory Overhead | Binary Size |
|---|---|---|---|
| Compile-Time (PHF) | 1-3 CPU cycles | Zero | Smaller |
| Runtime (HashMap) | 50-150 CPU cycles | Hash tables + allocations | Larger |
Benchmark Results:
Use when:
Benefits:
Use when:
Performance Cost:
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.
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
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
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
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();
# 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
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
// Combine static commands, YAML definitions, and runtime modules
let registry = CliBuilder::new()
.static_module_with_prefix( "core", "core", static_commands )
.dynamic_module_with_prefix( "plugins", "plugins", "plugins.yaml" )
.runtime_module_with_prefix( "custom", "ext", runtime_commands )
.build_hybrid();
| Approach | Lookup Time | Memory Overhead | Conflict Detection |
|---|---|---|---|
| Compile-Time | O(1) PHF | Zero | Build-time |
| Runtime | O(log n) | Hash tables | Runtime |
Aggregation Scaling:
See examples/practical_cli_aggregation.rs for a comprehensive demonstration showing:
# 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.
- name: "command_name" # Required: Command identifier
namespace: "optional.prefix" # Optional: Hierarchical organization
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
arguments:
- name: "count"
kind: "Integer"
validation_rules:
- Min: 1
- Max: 100
- name: "email"
kind: "String"
validation_rules:
- Pattern: "^[^@]+@[^@]+\\.[^@]+$"
- MinLength: 5
let result = pipeline.process_command_simple( ".namespace.command arg::value" );
if result.success
{
println!( "Success: {}", result.outputs[ 0 ].content );
}
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 );
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 );
}
}
}
unilang provides comprehensive help with three access methods:
.command ? # Instant help, bypasses validation
.command ?? # Clean help access
.command arg1::value ?? # Help with partial arguments
.command.help # Direct help command access
.namespace.command.help # Works with namespaced commands
[dependencies]
unilang = "0.10" # Default: enhanced_repl + simd + enabled
[dependencies]
unilang = { version = "0.10", features = ["simd", "enhanced_repl"] }
[dependencies]
unilang = { version = "0.10", default-features = false, features = ["enabled"] }
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_01_basic_compile_time.rs - PHF-based zero-cost lookupsstatic_02_yaml_build_integration.rs - Build script integration patternsstatic_03_performance_comparison.rs - Concrete performance measurementsstatic_04_multi_module_aggregation.rs - Modular command organization01_basic_command_registration.rs - Runtime registration patterns02_argument_types.rs - Comprehensive argument type examples07_yaml_json_loading.rs - Dynamic command loading18_help_conventions_demo.rs - Help system demonstrationfull_cli_example.rs - Complete CLI application12_repl_loop.rs - Basic REPL implementation15_interactive_repl_mode.rs - Interactive arguments and secure input17_advanced_repl_features.rs - History, auto-completion, error recoveryunilang 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:
Convert runtime CommandDefinition structures to YAML format.
Add compile-time generation to build.rs.
Replace CommandRegistry::new() with compile-time command registration via build.rs.
Use provided benchmarking examples to verify improvements.
See CONTRIBUTING.md for development guidelines.
Licensed under MIT license (LICENSE or https://opensource.org/licenses/MIT)