Skip to main content

card_stack/
requirements.rs

1use state_validation::{CollectedInputs, StateFilter};
2
3use crate::{
4    actions::ActionSource,
5    priority::{Priority, PriorityMut, PriorityStack},
6};
7
8pub trait ActionRequirement<State, Input> {
9    /// Satisfy the requirement.
10    type Filter: StateFilter<State, Input>;
11    /// All the possible inputs for the requirement (but does not necessarily pass the filter).
12    fn collect_inputs(state: &State) -> CollectedInputs<State, impl Iterator<Item = Input>>;
13}
14struct NoIter<Item>(std::marker::PhantomData<Item>);
15impl<Item> Iterator for NoIter<Item> {
16    type Item = Item;
17    fn next(&mut self) -> Option<Self::Item> {
18        None
19    }
20}
21impl<State> ActionRequirement<State, ()> for () {
22    type Filter = ();
23    fn collect_inputs(_state: &State) -> CollectedInputs<State, impl Iterator<Item = ()>> {
24        CollectedInputs::new(NoIter(std::marker::PhantomData::default()))
25    }
26}
27
28pub struct FulfilledAction<Action: crate::actions::ActionSource, Value> {
29    action: Action,
30    source: Action::Source,
31    value: Value,
32}
33
34impl<Action: crate::actions::ActionSource, Value> FulfilledAction<Action, Value> {
35    pub const fn new(action: Action, source: Action::Source, value: Value) -> Self {
36        FulfilledAction {
37            action,
38            source,
39            value,
40        }
41    }
42    pub fn take_action(self) -> Action {
43        self.action
44    }
45    pub fn source(&self) -> &Action::Source {
46        &self.source
47    }
48    pub fn value(&self) -> &Value {
49        &self.value
50    }
51}
52
53impl<Action: crate::actions::ActionSource, Value: Send + Sync> ActionSource
54    for FulfilledAction<Action, Value>
55{
56    type Source = Action::Source;
57    fn source(&self) -> &Self::Source {
58        self.action.source()
59    }
60}
61
62pub struct RequirementAction<Priority, Input, Action> {
63    priority: Priority,
64    action: Action,
65    _m: std::marker::PhantomData<Input>,
66}
67
68impl<Priority, Input, Action> RequirementAction<Priority, Input, Action> {
69    pub fn priority(&self) -> &Priority {
70        &self.priority
71    }
72    pub fn action(&self) -> &Action {
73        &self.action
74    }
75}
76impl<State, Input, Action: crate::actions::IncitingAction<State, Input>>
77    RequirementAction<Priority<State>, Input, Action>
78where
79    Action::Requirement: ActionRequirement<Priority<State>, Input>,
80{
81    /// If the current state has any inputs that fit the requirement,
82    /// return `Some`, otherwise `None`.
83    pub fn try_new(
84        priority: Priority<State>,
85        action: Action,
86    ) -> Result<
87        RequirementAction<Priority<State>, Input, Action>,
88        TryNewRequirementActionError<Priority<State>, Action>,
89    > {
90        let collected_inputs =
91            <Action::Requirement as ActionRequirement<Priority<State>, Input>>::collect_inputs(
92                &priority,
93            );
94        if collected_inputs
95            .fits_any::<<Action::Requirement as ActionRequirement<Priority<State>, Input>>::Filter>(
96            &priority,
97        ) {
98            Ok(RequirementAction {
99                priority,
100                action,
101                _m: std::marker::PhantomData::default(),
102            })
103        } else {
104            Err(TryNewRequirementActionError { priority, action })
105        }
106    }
107    pub fn select(
108        self,
109        value: Input,
110    ) -> Result<
111        Action::Resolved,
112        RequirementActionSelectionError<
113            Self,
114            <<Action::Requirement as ActionRequirement<Priority<State>, Input>>::Filter as StateFilter<Priority<State>, Input>>::Error,
115        >,
116    >{
117        let result = <<Action::Requirement as ActionRequirement<Priority<State>, Input>>::Filter as StateFilter<Priority<State>, Input>>::filter(
118            &self.priority,
119            value,
120        );
121        match result {
122            Ok(input) => Ok(self
123                .action
124                .resolve(PriorityMut::<Priority<State>>::new(self.priority), input)),
125            Err(error) => Err(RequirementActionSelectionError {
126                action: self,
127                error,
128            }),
129        }
130    }
131}
132#[derive(thiserror::Error)]
133#[error("requirement for action is impossible to fulfill")]
134pub struct TryNewRequirementActionError<Priority, Action> {
135    pub priority: Priority,
136    pub action: Action,
137}
138impl<Priority, Action> std::fmt::Debug for TryNewRequirementActionError<Priority, Action> {
139    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
140        write!(f, "requirement for action is impossible to fulfill")
141    }
142}
143impl<
144    State,
145    Input,
146    IncitingAction: crate::actions::IncitingActionInfo<State>,
147    Action: crate::actions::StackAction<State, Input, IncitingAction>,
148> RequirementAction<PriorityStack<State, IncitingAction>, Input, Action>
149where
150    Action::Requirement: ActionRequirement<PriorityStack<State, IncitingAction>, Input>,
151{
152    /// If the current state has any inputs that fit the requirement,
153    /// return `Some`, otherwise `None`.
154    pub fn try_new(
155        priority: PriorityStack<State, IncitingAction>,
156        action: Action,
157    ) -> Result<
158        RequirementAction<PriorityStack<State, IncitingAction>, Input, Action>,
159        TryNewRequirementActionError<PriorityStack<State, IncitingAction>, Action>,
160    > {
161        let collected_inputs = <Action::Requirement as ActionRequirement<
162            PriorityStack<State, IncitingAction>,
163            Input,
164        >>::collect_inputs(&priority);
165        if collected_inputs.fits_any::<<Action::Requirement as ActionRequirement<
166            PriorityStack<State, IncitingAction>,
167            Input,
168        >>::Filter>(&priority)
169        {
170            Ok(RequirementAction {
171                priority,
172                action,
173                _m: std::marker::PhantomData::default(),
174            })
175        } else {
176            Err(TryNewRequirementActionError { priority, action })
177        }
178    }
179    pub fn select(
180        self,
181        value: Input,
182    ) -> Result<
183        Action::Resolved,
184        RequirementActionSelectionError<
185            Self,
186            <<Action::Requirement as ActionRequirement<
187                PriorityStack<State, IncitingAction>,
188                Input,
189            >>::Filter as StateFilter<PriorityStack<State, IncitingAction>, Input>>::Error,
190        >,
191    > {
192        let result = <<Action::Requirement as ActionRequirement<
193            PriorityStack<State, IncitingAction>,
194            Input,
195        >>::Filter as StateFilter<PriorityStack<State, IncitingAction>, Input>>::filter(
196            &self.priority,
197            value,
198        );
199        match result {
200            Ok(input) => Ok(self.action.resolve(
201                PriorityMut::<PriorityStack<State, IncitingAction>>::new(self.priority),
202                input,
203            )),
204            Err(error) => Err(RequirementActionSelectionError {
205                action: self,
206                error,
207            }),
208        }
209    }
210}
211pub struct RequirementActionSelectionError<Action, E: std::error::Error> {
212    action: Action,
213    error: E,
214}
215impl<Action, E: std::error::Error> std::fmt::Debug for RequirementActionSelectionError<Action, E> {
216    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
217        std::fmt::Debug::fmt(&self.error, f)
218    }
219}
220impl<Action, E: std::error::Error> std::fmt::Display
221    for RequirementActionSelectionError<Action, E>
222{
223    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
224        std::fmt::Display::fmt(&self.error, f)
225    }
226}
227impl<Action, E: std::error::Error> RequirementActionSelectionError<Action, E> {
228    pub fn take_requirement_action(self) -> Action {
229        self.action
230    }
231    pub fn take_all(self) -> (Action, E) {
232        (self.action, self.error)
233    }
234    pub fn error(&self) -> &E {
235        &self.error
236    }
237}