state_validation/dynamic/
action.rs1use 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}