Expand description
Execution context module
This module provides traits and utilities for managing execution context in CLI/REPL applications built with dynamic-cli.
§Overview
The execution context is shared state that persists across command executions.
Each application defines its own context type that implements the
ExecutionContext trait.
§Key Concepts
§Execution Context
The context holds application-specific state that commands can read and modify:
use dynamic_cli::context::ExecutionContext;
use std::any::Any;
#[derive(Default)]
struct AppContext {
session_id: String,
user_data: Vec<String>,
settings: std::collections::HashMap<String, String>,
}
impl ExecutionContext for AppContext {
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}§Type-Safe Downcasting
Since the framework works with trait objects, commands must downcast the context to access their specific type:
use dynamic_cli::context::{ExecutionContext, downcast_mut};
fn my_command(context: &mut dyn ExecutionContext) -> Result<(), String> {
// Downcast to concrete type
let app_ctx = downcast_mut::<AppContext>(context)
.ok_or("Invalid context type")?;
// Use the context
app_ctx.counter += 1;
Ok(())
}§Thread Safety
All contexts must be Send + Sync to support:
- Multi-threaded command execution
- Async/await patterns
- Future framework extensibility
§Common Patterns
§Stateless Context
For simple applications that don’t need state:
use dynamic_cli::context::ExecutionContext;
use std::any::Any;
#[derive(Default)]
struct EmptyContext;
impl ExecutionContext for EmptyContext {
fn as_any(&self) -> &dyn Any { self }
fn as_any_mut(&mut self) -> &mut dyn Any { self }
}§Stateful Context
For applications that maintain state:
use dynamic_cli::context::ExecutionContext;
use std::any::Any;
use std::collections::HashMap;
struct DatabaseContext {
connection_pool: Vec<String>, // Simplified example
cache: HashMap<String, String>,
transaction_count: u64,
}
impl Default for DatabaseContext {
fn default() -> Self {
Self {
connection_pool: vec!["conn1".to_string()],
cache: HashMap::new(),
transaction_count: 0,
}
}
}
impl ExecutionContext for DatabaseContext {
fn as_any(&self) -> &dyn Any { self }
fn as_any_mut(&mut self) -> &mut dyn Any { self }
}§Error Handling in Commands
Best practice for handling downcast failures:
use dynamic_cli::context::{ExecutionContext, downcast_mut};
fn robust_handler(
context: &mut dyn ExecutionContext
) -> Result<(), Box<dyn std::error::Error>> {
let ctx = downcast_mut::<MyContext>(context)
.ok_or("Context type mismatch: expected MyContext")?;
ctx.value += 1;
Ok(())
}§Architecture Notes
§Why Use Trait Objects?
The framework uses dyn ExecutionContext because:
- Each application defines its own context type
- The framework can’t know concrete types at compile time
- This provides maximum flexibility for users
§Why Require Send + Sync?
Thread safety bounds enable:
- Sharing contexts across threads
- Compatibility with async runtimes (tokio, async-std)
- Future features like parallel command execution
§Performance Considerations
- Downcasting has minimal overhead (type ID comparison)
- Context access is not on the hot path for most commands
- The trait object indirection is negligible compared to I/O operations
§See Also
ExecutionContext: Core trait for contextsdowncast_ref(): Helper function for immutable downcastingdowncast_mut(): Helper function for mutable downcasting
Re-exports§
pub use traits::downcast_mut;pub use traits::downcast_ref;pub use traits::ExecutionContext;
Modules§
- traits
- Execution context traits