use std::marker::PhantomData;
use crate::command::CommandCallback;
use crate::context::Context;
use crate::error::{ClickError, Result};
pub struct PassDecorator<T> {
_marker: PhantomData<T>,
}
pub fn make_pass_decorator<T: 'static>() -> PassDecorator<T> {
PassDecorator {
_marker: PhantomData,
}
}
impl<T: 'static> PassDecorator<T> {
pub fn decorate<F>(self, f: F) -> CommandCallback
where
F: Fn(&T, &Context) -> Result<()> + Send + Sync + 'static,
{
Box::new(move |ctx: &Context| {
let obj = ctx.find_obj::<T>().ok_or_else(|| {
ClickError::usage("Missing context object for make_pass_decorator().")
})?;
f(obj, ctx)
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::context::ContextBuilder;
use std::sync::Arc;
#[derive(Debug)]
struct AppState {
value: i32,
}
#[test]
fn test_make_pass_decorator_passes_obj() {
let cb = make_pass_decorator::<AppState>().decorate(|state, _ctx| {
assert_eq!(state.value, 7);
Ok(())
});
let ctx = ContextBuilder::new().obj(AppState { value: 7 }).build();
cb(&ctx).unwrap();
}
#[test]
fn test_make_pass_decorator_finds_obj_from_parent() {
let cb = make_pass_decorator::<AppState>().decorate(|state, _ctx| {
assert_eq!(state.value, 9);
Ok(())
});
let parent = Arc::new(ContextBuilder::new().obj(AppState { value: 9 }).build());
let child = ContextBuilder::new().parent(parent).build();
cb(&child).unwrap();
}
}