Skip to main content

state_validation/dynamic/
action.rs

1use std::any::Any;
2
3use crate::{StateFilter, ValidAction, dynamic::DynStateFilter};
4
5pub struct DynValidAction<State, Input, Output> {
6    filter: DynStateFilter<State, Input, Box<dyn Any>>,
7    valid_action: Box<dyn DynAnyClone>,
8    action: for<'a> fn(Box<dyn Any>, State, Box<dyn Any>) -> Output,
9}
10impl<State, Input, Output> std::fmt::Debug for DynValidAction<State, Input, Output> {
11    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
12        f.debug_struct("DynValidAction").finish_non_exhaustive()
13    }
14}
15
16impl<State, Input, Output> DynValidAction<State, Input, Output> {
17    pub fn new<T: ValidAction<State, Input, Output = Output> + Clone + 'static>(
18        valid_action: T,
19    ) -> Self
20    where
21        <T::Filter as StateFilter<State, Input>>::ValidOutput: 'static,
22        <T::Filter as StateFilter<State, Input>>::Error: 'static,
23    {
24        DynValidAction {
25            filter: DynStateFilter::new_with_any_output::<T::Filter>(),
26            valid_action: Box::new(valid_action),
27            action: |valid_action, state, valid| {
28                T::with_valid_input(
29                    *valid_action.downcast().unwrap(),
30                    state,
31                    *valid.downcast().unwrap(),
32                )
33            },
34        }
35    }
36    pub fn filter(&self) -> &DynStateFilter<State, Input, Box<dyn Any>> {
37        &self.filter
38    }
39    pub fn execute_with_filter(
40        self,
41        state: State,
42        input: Input,
43    ) -> Result<Output, DynValidActionExecutionError<State>> {
44        match self.filter.filter(&state, input) {
45            Ok(v) => Ok((self.action)(self.valid_action, state, v)),
46            Err(error) => Err(DynValidActionExecutionError { state, error }),
47        }
48    }
49}
50
51#[derive(Debug, thiserror::Error)]
52pub struct DynValidActionExecutionError<State> {
53    pub state: State,
54    #[source]
55    pub error: Box<dyn std::error::Error>,
56}
57
58impl<State, Input, Output> ValidAction<State, Input> for DynValidAction<State, Input, Output> {
59    type Filter = ();
60    type Output = Result<Output, DynValidActionExecutionError<State>>;
61    fn with_valid_input(self, state: State, input: Input) -> Self::Output {
62        self.execute_with_filter(state, input)
63    }
64}
65
66impl<State, Input, Output> Clone for DynValidAction<State, Input, Output> {
67    fn clone(&self) -> Self {
68        DynValidAction {
69            filter: self.filter.clone(),
70            valid_action: (*self.valid_action).any_clone(),
71            action: self.action,
72        }
73    }
74}
75trait DynAnyClone: Any {
76    fn any_clone(&self) -> Box<dyn DynAnyClone>;
77}
78impl<T: Clone + 'static> DynAnyClone for T {
79    fn any_clone(&self) -> Box<dyn DynAnyClone> {
80        Box::new(self.clone())
81    }
82}