event_trigger_action_system/
triggers.rs

1use crate::TriggerCondition;
2use crate::conditions::{CompiledTriggerCondition, TriggerConditionUpdate};
3use btreemultimap_value_ord::BTreeMultiMap;
4use conditional_serde::ConditionalSerde;
5#[cfg(feature = "serde")]
6use serde::{Deserialize, Serialize};
7use std::cmp::Ordering;
8use std::collections::{BTreeMap, VecDeque};
9use std::fmt::Debug;
10
11mod std_lib_implementations;
12
13/// A raw collection of triggers.
14#[derive(Debug, Clone)]
15pub struct Triggers<Event, Action> {
16    triggers: Vec<Trigger<Event, Action>>,
17}
18
19/// A compiled collection of triggers.
20///
21/// This is the central type for using the event trigger action system.
22/// Execute events via [`Self::execute_event`], [`Self::execute_events`] and [`Self::execute_owned_events`], and collect actions via [`Self::consume_action`] and [`Self::consume_all_actions`].
23#[derive(Debug, Clone)]
24#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
25pub struct CompiledTriggers<Event: TriggerEvent> {
26    trigger_system: TriggerSystem<Event>,
27    action_queue: VecDeque<Event::Action>,
28}
29
30#[derive(Debug, Clone)]
31#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
32struct TriggerSystem<Event: TriggerEvent> {
33    triggers: Vec<CompiledTrigger<Event>>,
34    subscriptions: BTreeMultiMap<Event::Identifier, usize>,
35}
36
37/// A raw trigger.
38#[derive(Debug, Clone)]
39pub struct Trigger<Event, Action> {
40    /// A unique identifier of the trigger.
41    pub id_str: String,
42    /// The condition for the trigger to trigger.
43    pub condition: TriggerCondition<Event>,
44    /// The actions the trigger executes when triggered.
45    pub actions: Vec<Action>,
46}
47
48/// A compiled trigger.
49#[derive(Debug, Clone)]
50#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
51pub struct CompiledTrigger<Event: TriggerEvent> {
52    /// A unique identifier of the trigger.
53    pub id_str: String,
54    condition: CompiledTriggerCondition<Event>,
55    actions: Option<Vec<Event::Action>>,
56}
57
58/// A handle of a trigger.
59///
60/// This allows to identify a trigger without worrying about lifetimes.
61#[derive(Debug, Clone, Copy, Default, Eq, PartialEq, Hash, Ord, PartialOrd)]
62#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
63pub struct TriggerHandle(usize);
64
65/// A trigger action.
66pub trait TriggerAction: Debug + Clone {}
67
68/// An identifier of a trigger.
69///
70/// This is used to compare triggers while ignoring their progress towards fulfilling a comparison.
71/// Hence, the identifier should ignore all data that is used to make a comparison between [`TriggerEvents`](TriggerEvent),
72/// but keep all data that is used to decide comparability between [`TriggerEvents`](TriggerEvent).
73///
74/// Formally, the following invariant must be fulfilled: if [`partial_cmp`](PartialOrd::partial_cmp) between two trigger events returns `None`,
75/// then their identifiers must be different, and vice versa.
76///
77/// This type should be cheap to clone.
78pub trait TriggerEventIdentifier: Debug + Ord + Clone {}
79
80/// A trigger event.
81pub trait TriggerEvent: From<Self::Action> + PartialOrd {
82    /// The action type used by the trigger event.
83    type Action: TriggerAction + ConditionalSerde;
84
85    /// The identifier of a trigger event.
86    ///
87    /// See [`TriggerEventIdentifier`] for details.
88    type Identifier: TriggerEventIdentifier + ConditionalSerde;
89
90    /// Returns the identifier of this trigger event.
91    fn identifier(&self) -> Self::Identifier;
92
93    /// Returns a number between 0.0 and 1.0 indicating how close the ordering of this and other is to the target ordering.
94    /// If the events are not ordered, then `None` is returned.
95    ///
96    /// If progress reporting is not needed when using this library, feel free to stick with the default implementation of this method.
97    fn partial_cmp_progress(&self, other: &Self, target_ordering: Ordering) -> Option<f64> {
98        self.partial_cmp(other).map(|ordering| {
99            if ordering == target_ordering {
100                1.0
101            } else {
102                0.0
103            }
104        })
105    }
106}
107
108impl<Event, Action> Triggers<Event, Action> {
109    /// Create a new raw triggers instance.
110    pub fn new(triggers: Vec<Trigger<Event, Action>>) -> Self {
111        Self { triggers }
112    }
113
114    /// Compile the raw triggers.
115    ///
116    /// Events are compiled by the event compiler, and actions are compiled by the action compiler.
117    pub fn compile<
118        EventCompiler: Fn(Event) -> CompiledEvent,
119        CompiledEvent: TriggerEvent,
120        ActionCompiler: Fn(Action) -> CompiledEvent::Action,
121    >(
122        self,
123        event_compiler: &EventCompiler,
124        action_compiler: &ActionCompiler,
125    ) -> CompiledTriggers<CompiledEvent> {
126        CompiledTriggers::new(
127            self.triggers
128                .into_iter()
129                .map(|trigger| trigger.compile(event_compiler, action_compiler))
130                .collect(),
131        )
132    }
133}
134
135impl<Event: TriggerEvent> CompiledTriggers<Event> {
136    pub(crate) fn new(mut triggers: Vec<CompiledTrigger<Event>>) -> Self {
137        let mut initial_actions = Vec::new();
138        let subscriptions = triggers
139            .iter_mut()
140            .enumerate()
141            .flat_map(|(id, trigger)| {
142                let subscriptions = trigger.subscriptions();
143                if trigger.completed() {
144                    initial_actions.append(&mut trigger.consume_actions());
145                }
146                subscriptions
147                    .into_iter()
148                    .map(move |identifier| (identifier, id))
149            })
150            .collect();
151        let mut trigger_system = TriggerSystem {
152            triggers,
153            subscriptions,
154        };
155
156        let mut i = 0;
157        while i < initial_actions.len() {
158            initial_actions.append(
159                &mut trigger_system.execute_event(&Event::from(initial_actions[i].clone())),
160            );
161            i += 1;
162        }
163
164        Self {
165            trigger_system,
166            action_queue: initial_actions.into_iter().collect(),
167        }
168    }
169
170    /// Execute the given event.
171    ///
172    /// The event is executed right away, and all resulting actions are stored in an internal action queue,
173    /// waiting to be retrieved via [`Self::consume_action`] or [`Self::consume_all_actions`].
174    pub fn execute_event(&mut self, event: &Event) {
175        self.action_queue
176            .extend(self.trigger_system.execute_event(event));
177    }
178
179    /// Execute the given events.
180    ///
181    /// The event is executed right away, and all resulting actions are stored in an internal action queue,
182    /// waiting to be retrieved via [`Self::consume_action`] or [`Self::consume_all_actions`].
183    pub fn execute_events<'events>(&mut self, events: impl IntoIterator<Item = &'events Event>)
184    where
185        Event: 'events,
186    {
187        events
188            .into_iter()
189            .for_each(|event| self.execute_event(event));
190    }
191
192    /// Execute the given owned events.
193    ///
194    /// The event is executed right away, and all resulting actions are stored in an internal action queue,
195    /// waiting to be retrieved via [`Self::consume_action`] or [`Self::consume_all_actions`].
196    ///
197    /// This method is no different from [`Self::execute_events`], except that it drops the given events after execution.
198    pub fn execute_owned_events(&mut self, events: impl IntoIterator<Item = Event>) {
199        events
200            .into_iter()
201            .for_each(|event| self.execute_event(&event));
202    }
203
204    /// Consume an action from the action queue, if there is one.
205    pub fn consume_action(&mut self) -> Option<Event::Action> {
206        self.action_queue.pop_front()
207    }
208
209    /// Consume all action from the action queue.
210    ///
211    /// If the returned iterator is dropped before all actions are consumed, the remaining actions are dropped quietly.
212    pub fn consume_all_actions(&mut self) -> impl '_ + Iterator<Item = Event::Action> {
213        self.action_queue.drain(0..self.action_queue.len())
214    }
215
216    /// Returns the progress of the given trigger as `(current_progress, required_progress)`.
217    ///
218    /// When `current_progress` reaches `required_progress`, then the trigger triggers.
219    pub fn progress(&self, handle: TriggerHandle) -> Option<(f64, f64)> {
220        self.trigger_system
221            .triggers
222            .get(handle.0)
223            .map(|trigger| trigger.progress())
224    }
225}
226
227impl<Event: TriggerEvent> TriggerSystem<Event> {
228    fn execute_event(&mut self, event: &Event) -> Vec<Event::Action> {
229        let mut all_actions = Vec::new();
230        let identifier = event.identifier();
231        let trigger_indices: Vec<_> = self
232            .subscriptions
233            .get(&identifier)
234            .unwrap_or(&BTreeMap::new())
235            .keys()
236            .copied()
237            .collect();
238        for trigger_index in trigger_indices {
239            let trigger = &mut self.triggers[trigger_index];
240            let (mut actions, trigger_condition_updates) = trigger.execute_event(event);
241            all_actions.append(&mut actions);
242
243            for trigger_condition_update in trigger_condition_updates {
244                match trigger_condition_update {
245                    TriggerConditionUpdate::Subscribe(identifier) => {
246                        self.subscriptions.insert(identifier.clone(), trigger_index);
247                    }
248                    TriggerConditionUpdate::Unsubscribe(identifier) => {
249                        self.subscriptions
250                            .remove_key_value(&identifier, &trigger_index);
251                    }
252                }
253            }
254        }
255
256        let mut i = 0;
257        while i < all_actions.len() {
258            all_actions.append(&mut self.execute_event(&Event::from(all_actions[i].clone())));
259            i += 1;
260        }
261
262        all_actions
263    }
264}
265
266impl<Event, Action> Trigger<Event, Action> {
267    /// Creates a new raw trigger.
268    pub fn new(id_str: String, condition: TriggerCondition<Event>, actions: Vec<Action>) -> Self {
269        Self {
270            id_str,
271            condition,
272            actions,
273        }
274    }
275
276    /// Compiles this trigger.
277    ///
278    /// Events are compiled by the event compiler, and actions are compiled by the action compiler.
279    pub fn compile<
280        EventCompiler: Fn(Event) -> CompiledEvent,
281        CompiledEvent: TriggerEvent,
282        ActionCompiler: Fn(Action) -> CompiledEvent::Action,
283    >(
284        self,
285        event_compiler: &EventCompiler,
286        action_compiler: &ActionCompiler,
287    ) -> CompiledTrigger<CompiledEvent> {
288        CompiledTrigger::new(
289            self.id_str,
290            self.condition.compile(event_compiler),
291            self.actions.into_iter().map(action_compiler).collect(),
292        )
293    }
294}
295
296impl<Event: TriggerEvent> CompiledTrigger<Event> {
297    pub(crate) fn new(
298        id_str: String,
299        condition: CompiledTriggerCondition<Event>,
300        actions: Vec<Event::Action>,
301    ) -> Self {
302        Self {
303            id_str,
304            condition,
305            actions: Some(actions),
306        }
307    }
308
309    pub(crate) fn subscriptions(&self) -> Vec<Event::Identifier> {
310        self.condition.subscriptions()
311    }
312
313    pub(crate) fn execute_event(
314        &mut self,
315        event: &Event,
316    ) -> (
317        Vec<Event::Action>,
318        Vec<TriggerConditionUpdate<Event::Identifier>>,
319    ) {
320        let (trigger_condition_updates, result, _) = self.condition.execute_event(event);
321        if result {
322            (self.actions.take().unwrap(), trigger_condition_updates)
323        } else {
324            (Default::default(), trigger_condition_updates)
325        }
326    }
327
328    pub(crate) fn progress(&self) -> (f64, f64) {
329        (
330            self.condition.current_progress(),
331            self.condition.required_progress(),
332        )
333    }
334
335    /// Returns the trigger condition of this trigger.
336    #[allow(dead_code)]
337    pub(crate) fn condition(&self) -> &CompiledTriggerCondition<Event> {
338        &self.condition
339    }
340
341    /// Returns the actions of this trigger.
342    #[allow(dead_code)]
343    pub(crate) fn actions(&self) -> &[Event::Action] {
344        self.actions.as_deref().unwrap_or(&[])
345    }
346
347    pub(crate) fn completed(&self) -> bool {
348        self.condition.completed()
349    }
350
351    fn consume_actions(&mut self) -> Vec<Event::Action> {
352        self.actions.take().unwrap()
353    }
354}
355
356impl From<usize> for TriggerHandle {
357    fn from(value: usize) -> Self {
358        Self(value)
359    }
360}