use std::any::Any;
pub trait ExecutionContext: Send + Sync {
fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any;
}
pub fn downcast_ref<T: ExecutionContext + 'static>(context: &dyn ExecutionContext) -> Option<&T> {
context.as_any().downcast_ref::<T>()
}
pub fn downcast_mut<T: ExecutionContext + 'static>(
context: &mut dyn ExecutionContext,
) -> Option<&mut T> {
context.as_any_mut().downcast_mut::<T>()
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Default, Debug, PartialEq)]
struct TestContext {
value: i32,
name: String,
}
impl ExecutionContext for TestContext {
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
#[derive(Default)]
struct OtherContext {
data: Vec<u8>,
}
impl ExecutionContext for OtherContext {
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
#[test]
fn test_basic_context_implementation() {
let ctx = TestContext {
value: 42,
name: "test".to_string(),
};
assert_eq!(ctx.value, 42);
assert_eq!(ctx.name, "test");
}
#[test]
fn test_as_any_conversion() {
let ctx = TestContext::default();
let any_ref = ctx.as_any();
let downcasted = any_ref.downcast_ref::<TestContext>();
assert!(downcasted.is_some());
assert_eq!(downcasted.unwrap().value, 0);
}
#[test]
fn test_as_any_mut_conversion() {
let mut ctx = TestContext::default();
let any_mut = ctx.as_any_mut();
if let Some(test_ctx) = any_mut.downcast_mut::<TestContext>() {
test_ctx.value = 100;
}
assert_eq!(ctx.value, 100);
}
#[test]
fn test_downcast_ref_success() {
let ctx = TestContext {
value: 42,
name: "test".to_string(),
};
let ctx_ref: &dyn ExecutionContext = &ctx;
let downcasted = downcast_ref::<TestContext>(ctx_ref);
assert!(downcasted.is_some());
let concrete = downcasted.unwrap();
assert_eq!(concrete.value, 42);
assert_eq!(concrete.name, "test");
}
#[test]
fn test_downcast_ref_failure() {
let ctx = TestContext::default();
let ctx_ref: &dyn ExecutionContext = &ctx;
let downcasted = downcast_ref::<OtherContext>(ctx_ref);
assert!(downcasted.is_none());
}
#[test]
fn test_downcast_mut_success() {
let mut ctx = TestContext {
value: 10,
name: "initial".to_string(),
};
let ctx_mut: &mut dyn ExecutionContext = &mut ctx;
if let Some(concrete) = downcast_mut::<TestContext>(ctx_mut) {
concrete.value = 20;
concrete.name = "modified".to_string();
}
assert_eq!(ctx.value, 20);
assert_eq!(ctx.name, "modified");
}
#[test]
fn test_downcast_mut_failure() {
let mut ctx = TestContext::default();
let ctx_mut: &mut dyn ExecutionContext = &mut ctx;
let downcasted = downcast_mut::<OtherContext>(ctx_mut);
assert!(downcasted.is_none());
}
#[test]
fn test_multiple_downcasts() {
let mut ctx = TestContext::default();
{
let ctx_mut: &mut dyn ExecutionContext = &mut ctx;
if let Some(concrete) = downcast_mut::<TestContext>(ctx_mut) {
concrete.value = 1;
}
}
{
let ctx_mut: &mut dyn ExecutionContext = &mut ctx;
if let Some(concrete) = downcast_mut::<TestContext>(ctx_mut) {
concrete.value += 1;
}
}
assert_eq!(ctx.value, 2);
}
#[test]
fn test_context_is_send_sync() {
fn assert_send<T: Send>() {}
fn assert_sync<T: Sync>() {}
assert_send::<TestContext>();
assert_sync::<TestContext>();
assert_send::<Box<dyn ExecutionContext>>();
assert_sync::<Box<dyn ExecutionContext>>();
}
#[test]
fn test_realistic_handler_scenario() {
fn handler(ctx: &mut dyn ExecutionContext, increment: i32) -> Result<(), String> {
let concrete = downcast_mut::<TestContext>(ctx).ok_or("Invalid context type")?;
concrete.value += increment;
Ok(())
}
let mut ctx = TestContext::default();
handler(&mut ctx, 10).unwrap();
handler(&mut ctx, 20).unwrap();
handler(&mut ctx, 30).unwrap();
assert_eq!(ctx.value, 60);
}
#[test]
fn test_handler_with_wrong_context_type() {
fn handler(ctx: &mut dyn ExecutionContext) -> Result<(), String> {
downcast_mut::<TestContext>(ctx).ok_or("Wrong context type")?;
Ok(())
}
let mut ctx = OtherContext::default();
let result = handler(&mut ctx);
assert!(result.is_err());
assert_eq!(result.unwrap_err(), "Wrong context type");
}
#[derive(Default)]
struct ComplexContext {
counters: std::collections::HashMap<String, u64>,
flags: Vec<bool>,
optional_data: Option<String>,
}
impl ExecutionContext for ComplexContext {
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
#[test]
fn test_complex_context_operations() {
let mut ctx = ComplexContext::default();
ctx.counters.insert("visits".to_string(), 0);
ctx.flags.push(true);
ctx.optional_data = Some("data".to_string());
let ctx_ref: &mut dyn ExecutionContext = &mut ctx;
if let Some(complex) = downcast_mut::<ComplexContext>(ctx_ref) {
*complex.counters.get_mut("visits").unwrap() += 1;
complex.flags[0] = false;
complex.optional_data = None;
}
assert_eq!(*ctx.counters.get("visits").unwrap(), 1);
assert_eq!(ctx.flags[0], false);
assert!(ctx.optional_data.is_none());
}
#[test]
fn test_pattern_matching_with_downcast() {
let mut ctx = TestContext {
value: 0,
name: String::new(),
};
let ctx_ref: &mut dyn ExecutionContext = &mut ctx;
match downcast_mut::<TestContext>(ctx_ref) {
Some(test_ctx) => {
test_ctx.value = 42;
test_ctx.name = "success".to_string();
}
None => panic!("Downcast failed"),
}
assert_eq!(ctx.value, 42);
assert_eq!(ctx.name, "success");
}
#[test]
fn test_option_combinators_with_downcast() {
let ctx = TestContext {
value: 100,
name: "test".to_string(),
};
let ctx_ref: &dyn ExecutionContext = &ctx;
let value = downcast_ref::<TestContext>(ctx_ref)
.map(|c| c.value)
.unwrap_or(0);
assert_eq!(value, 100);
}
#[test]
fn test_default_implementation() {
let ctx = TestContext::default();
assert_eq!(ctx.value, 0);
assert_eq!(ctx.name, "");
}
}