event_trigger_action_system/
conditions.rs

1use std::cmp::Ordering;
2
3use crate::triggers::TriggerEvent;
4#[cfg(feature = "serde")]
5use serde::{Deserialize, Serialize};
6
7/// The (uncompiled) trigger conditions for events.
8///
9/// Each condition triggers at most once.
10#[derive(Debug, Clone, Eq, PartialEq)]
11pub enum TriggerCondition<Event> {
12    /// No trigger condition, this condition is always fulfilled.
13    None,
14
15    /// The unfulfillable trigger condition. This condition is never fulfilled.
16    Never,
17
18    /// Trigger after a certain number of events have been received.
19    EventCount {
20        /// The event to count.
21        event: Event,
22        /// The amount of times this event needs to be received for the condition to trigger.
23        required: usize,
24    },
25
26    /// Trigger when an event is received that is greater than the reference event.
27    Greater {
28        /// The reference event to compare against.
29        reference_event: Event,
30    },
31
32    /// Trigger when an event is received that is greater than or equal to the reference event.
33    GreaterOrEqual {
34        /// The reference event to compare against.
35        reference_event: Event,
36    },
37
38    /// Trigger when an event is received that is equal to the reference event.
39    Equal {
40        /// The reference event to compare against.
41        reference_event: Event,
42    },
43
44    /// Trigger when an event is received that is less than or equal to the reference event.
45    LessOrEqual {
46        /// The reference event to compare against.
47        reference_event: Event,
48    },
49
50    /// Trigger when an event is received that is less than the reference event.
51    Less {
52        /// The reference event to compare against.
53        reference_event: Event,
54    },
55
56    /// Trigger when the given conditions have been fulfilled in sequence.
57    ///
58    /// This works by having a pointer to the current active condition in the sequence.
59    /// Whenever a condition is fulfilled, the pointer gets moved to the right.
60    /// If it has visited all conditions, then this condition triggers.
61    Sequence {
62        /// The sequence of conditions.
63        conditions: Vec<TriggerCondition<Event>>,
64    },
65
66    /// Triggers after all given conditions have been fulfilled in any order.
67    ///
68    /// This can be constructed via the `BitAnd` operator.
69    ///
70    /// Compared to [`Self::Sequence`](TriggerCondition::Sequence), this does not require to fulfil the conditions in any order.
71    ///
72    /// # Example
73    ///
74    /// ```rust
75    /// use event_trigger_action_system::*;
76    ///
77    /// assert_eq!(none() & never(), TriggerCondition::<()>::And {conditions: vec![none(), never()]});
78    /// ```
79    And {
80        /// The conditions to fulfil.
81        conditions: Vec<TriggerCondition<Event>>,
82    },
83
84    /// Triggers after one of the given conditions have been fulfilled.
85    ///
86    /// This can be constructed via the `BitOr` operator.
87    ///
88    /// # Example
89    ///
90    /// ```rust
91    /// use event_trigger_action_system::*;
92    ///
93    /// assert_eq!(none() | never(), TriggerCondition::<()>::Or {conditions: vec![none(), never()]});
94    /// ```
95    Or {
96        /// The conditions to fulfil.
97        conditions: Vec<TriggerCondition<Event>>,
98    },
99
100    /// Triggers after a given number of the given conditions have been fulfilled.
101    AnyN {
102        /// The conditions to fulfil.
103        conditions: Vec<TriggerCondition<Event>>,
104        /// The amount of conditions that need to be fulfilled.
105        n: usize,
106    },
107}
108
109/// A compiled trigger condition.
110///
111/// This
112#[derive(Debug, Clone)]
113#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
114pub struct CompiledTriggerCondition<Event: TriggerEvent> {
115    pub(crate) kind: CompiledTriggerConditionKind<Event>,
116    pub(crate) completed: bool,
117    pub(crate) required_progress: f64,
118    pub(crate) current_progress: f64,
119}
120
121#[derive(Debug, Clone)]
122#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
123pub(crate) enum CompiledTriggerConditionKind<Event: TriggerEvent> {
124    None,
125    Never,
126    EventCount {
127        identifier: Event::Identifier,
128        count: usize,
129        required: usize,
130    },
131    Greater {
132        reference_event: Event,
133        fulfilled: bool,
134    },
135    GreaterOrEqual {
136        reference_event: Event,
137        fulfilled: bool,
138    },
139    Equal {
140        reference_event: Event,
141        fulfilled: bool,
142    },
143    LessOrEqual {
144        reference_event: Event,
145        fulfilled: bool,
146    },
147    Less {
148        reference_event: Event,
149        fulfilled: bool,
150    },
151    Sequence {
152        current_index: usize,
153        conditions: Vec<CompiledTriggerCondition<Event>>,
154    },
155    And {
156        conditions: Vec<CompiledTriggerCondition<Event>>,
157        fulfilled_conditions: Vec<CompiledTriggerCondition<Event>>,
158    },
159    Or {
160        conditions: Vec<CompiledTriggerCondition<Event>>,
161        fulfilled_conditions: Vec<CompiledTriggerCondition<Event>>,
162    },
163    AnyN {
164        conditions: Vec<CompiledTriggerCondition<Event>>,
165        fulfilled_conditions: Vec<CompiledTriggerCondition<Event>>,
166        n: usize,
167    },
168}
169
170#[derive(Debug, Clone, Eq, PartialEq)]
171#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
172pub enum TriggerConditionUpdate<Identifier> {
173    Subscribe(Identifier),
174    Unsubscribe(Identifier),
175}
176
177impl<Event> TriggerCondition<Event> {
178    /// Compile this trigger condition.
179    ///
180    /// Raw event information is transformed into a more compact identifier for a matching compiled event.
181    pub fn compile<EventCompiler: Fn(Event) -> CompiledEvent, CompiledEvent: TriggerEvent>(
182        self,
183        event_compiler: &EventCompiler,
184    ) -> CompiledTriggerCondition<CompiledEvent> {
185        CompiledTriggerCondition::new(match self {
186            TriggerCondition::None => CompiledTriggerConditionKind::None,
187            TriggerCondition::Never => CompiledTriggerConditionKind::Never,
188            TriggerCondition::EventCount { event, required } => {
189                CompiledTriggerConditionKind::EventCount {
190                    identifier: event_compiler(event).identifier(),
191                    count: 0,
192                    required,
193                }
194            }
195            TriggerCondition::Greater { reference_event } => {
196                CompiledTriggerConditionKind::Greater {
197                    reference_event: event_compiler(reference_event),
198                    fulfilled: false,
199                }
200            }
201            TriggerCondition::GreaterOrEqual { reference_event } => {
202                CompiledTriggerConditionKind::GreaterOrEqual {
203                    reference_event: event_compiler(reference_event),
204                    fulfilled: false,
205                }
206            }
207            TriggerCondition::Equal { reference_event } => CompiledTriggerConditionKind::Equal {
208                reference_event: event_compiler(reference_event),
209                fulfilled: false,
210            },
211            TriggerCondition::LessOrEqual { reference_event } => {
212                CompiledTriggerConditionKind::LessOrEqual {
213                    reference_event: event_compiler(reference_event),
214                    fulfilled: false,
215                }
216            }
217            TriggerCondition::Less { reference_event } => CompiledTriggerConditionKind::Less {
218                reference_event: event_compiler(reference_event),
219                fulfilled: false,
220            },
221            TriggerCondition::Sequence { conditions } => {
222                let conditions = conditions
223                    .into_iter()
224                    .map(|condition| {
225                        let condition = condition.compile(event_compiler);
226                        // Sequences are not allowed to contain `None` conditions.
227                        assert!(!condition.completed());
228                        condition
229                    })
230                    .collect();
231                CompiledTriggerConditionKind::Sequence {
232                    current_index: 0,
233                    conditions,
234                }
235            }
236            TriggerCondition::And { conditions } => {
237                let mut compiled_conditions = Vec::new();
238                let mut compiled_fulfilled_conditions = Vec::new();
239                for condition in conditions {
240                    let compiled_condition = condition.compile(event_compiler);
241                    if compiled_condition.completed() {
242                        compiled_fulfilled_conditions.push(compiled_condition);
243                    } else {
244                        compiled_conditions.push(compiled_condition);
245                    }
246                }
247                CompiledTriggerConditionKind::And {
248                    conditions: compiled_conditions,
249                    fulfilled_conditions: compiled_fulfilled_conditions,
250                }
251            }
252            TriggerCondition::Or { conditions } => {
253                let mut compiled_conditions = Vec::new();
254                let mut compiled_fulfilled_conditions = Vec::new();
255                for condition in conditions {
256                    let compiled_condition = condition.compile(event_compiler);
257                    if compiled_condition.completed() {
258                        compiled_fulfilled_conditions.push(compiled_condition);
259                    } else {
260                        compiled_conditions.push(compiled_condition);
261                    }
262                }
263                CompiledTriggerConditionKind::Or {
264                    conditions: compiled_conditions,
265                    fulfilled_conditions: compiled_fulfilled_conditions,
266                }
267            }
268            TriggerCondition::AnyN { conditions, n } => {
269                let mut compiled_conditions = Vec::new();
270                let mut compiled_fulfilled_conditions = Vec::new();
271                for condition in conditions {
272                    let compiled_condition = condition.compile(event_compiler);
273                    if compiled_condition.completed() {
274                        compiled_fulfilled_conditions.push(compiled_condition);
275                    } else {
276                        compiled_conditions.push(compiled_condition);
277                    }
278                }
279                CompiledTriggerConditionKind::AnyN {
280                    conditions: compiled_conditions,
281                    fulfilled_conditions: compiled_fulfilled_conditions,
282                    n,
283                }
284            }
285        })
286    }
287}
288
289impl<Event: TriggerEvent> CompiledTriggerCondition<Event> {
290    pub(crate) fn new(kind: CompiledTriggerConditionKind<Event>) -> Self {
291        Self {
292            required_progress: kind.required_progress(),
293            current_progress: 0.0,
294            completed: kind.completed(),
295            kind,
296        }
297    }
298
299    /// Returns the required progress of the compiled trigger condition.
300    pub fn required_progress(&self) -> f64 {
301        self.required_progress
302    }
303
304    /// Returns the current progress of the compiled trigger condition.
305    pub fn current_progress(&self) -> f64 {
306        assert!(self.current_progress.is_finite());
307        self.current_progress
308    }
309
310    /// Returns true if the compiled trigger condition is completed.
311    pub fn completed(&self) -> bool {
312        self.completed
313    }
314
315    pub(crate) fn execute_event(
316        &mut self,
317        event: &Event,
318    ) -> (Vec<TriggerConditionUpdate<Event::Identifier>>, bool, f64) {
319        assert!(!self.completed);
320        let (trigger_condition_update, result, current_progress) = self.kind.execute_event(event);
321        assert!(current_progress >= self.current_progress - 1e-6);
322        self.current_progress = current_progress;
323        self.completed = result;
324        (trigger_condition_update, result, self.current_progress)
325    }
326
327    pub(crate) fn subscriptions(&self) -> Vec<Event::Identifier> {
328        if self.completed {
329            return Default::default();
330        }
331
332        match &self.kind {
333            CompiledTriggerConditionKind::None => Default::default(),
334            CompiledTriggerConditionKind::Never => Default::default(),
335            CompiledTriggerConditionKind::EventCount { identifier, .. } => vec![identifier.clone()],
336            CompiledTriggerConditionKind::Greater {
337                reference_event, ..
338            }
339            | CompiledTriggerConditionKind::GreaterOrEqual {
340                reference_event, ..
341            }
342            | CompiledTriggerConditionKind::Equal {
343                reference_event, ..
344            }
345            | CompiledTriggerConditionKind::LessOrEqual {
346                reference_event, ..
347            }
348            | CompiledTriggerConditionKind::Less {
349                reference_event, ..
350            } => vec![reference_event.identifier()],
351            CompiledTriggerConditionKind::Sequence {
352                current_index,
353                conditions,
354            } => conditions[*current_index].subscriptions(),
355            CompiledTriggerConditionKind::And { conditions, .. }
356            | CompiledTriggerConditionKind::Or { conditions, .. }
357            | CompiledTriggerConditionKind::AnyN { conditions, .. } => conditions
358                .iter()
359                .flat_map(|condition| condition.subscriptions())
360                .collect(),
361        }
362    }
363}
364
365impl<Event: TriggerEvent> CompiledTriggerConditionKind<Event> {
366    fn required_progress(&self) -> f64 {
367        match self {
368            Self::None => 0.0,
369            Self::Never
370            | Self::Greater { .. }
371            | Self::GreaterOrEqual { .. }
372            | Self::Equal { .. }
373            | Self::LessOrEqual { .. }
374            | Self::Less { .. } => 1.0,
375            Self::EventCount { required, .. } => *required as f64,
376            Self::Sequence { conditions, .. } => conditions
377                .iter()
378                .map(|condition| condition.required_progress())
379                .sum(),
380            Self::And {
381                conditions,
382                fulfilled_conditions,
383            } => conditions
384                .iter()
385                .chain(fulfilled_conditions.iter())
386                .map(|condition| condition.required_progress())
387                .sum(),
388            Self::Or {
389                conditions,
390                fulfilled_conditions,
391            } => conditions
392                .iter()
393                .chain(fulfilled_conditions.iter())
394                .map(|condition| condition.required_progress())
395                .min_by(|a, b| a.partial_cmp(b).unwrap())
396                .unwrap_or(0.0),
397            Self::AnyN {
398                conditions,
399                fulfilled_conditions,
400                n,
401            } => {
402                let mut required_progresses: Vec<_> = conditions
403                    .iter()
404                    .chain(fulfilled_conditions.iter())
405                    .map(|condition| condition.required_progress())
406                    .collect();
407                required_progresses.sort_unstable_by(|a, b| a.partial_cmp(b).unwrap());
408                required_progresses.iter().take(*n).sum()
409            }
410        }
411    }
412
413    fn completed(&self) -> bool {
414        match self {
415            Self::None => true,
416            Self::Never => false,
417            Self::EventCount {
418                count, required, ..
419            } => count >= required,
420            Self::Greater { fulfilled, .. }
421            | Self::GreaterOrEqual { fulfilled, .. }
422            | Self::Equal { fulfilled, .. }
423            | Self::LessOrEqual { fulfilled, .. }
424            | Self::Less { fulfilled, .. } => *fulfilled,
425            Self::Sequence {
426                current_index,
427                conditions,
428            } => *current_index >= conditions.len(),
429            Self::And { conditions, .. } => conditions.is_empty(),
430            Self::Or { conditions, .. } => conditions.is_empty(),
431            Self::AnyN {
432                fulfilled_conditions,
433                n,
434                ..
435            } => fulfilled_conditions.len() >= *n,
436        }
437    }
438
439    fn execute_event(
440        &mut self,
441        event: &Event,
442    ) -> (Vec<TriggerConditionUpdate<Event::Identifier>>, bool, f64) {
443        match self {
444            Self::None => (Default::default(), true, 0.0),
445            Self::Never => (Default::default(), false, 0.0),
446            Self::EventCount {
447                identifier: counted_identifier,
448                count,
449                required,
450            } => {
451                assert!(count < required);
452                let identifier = event.identifier();
453                if *counted_identifier == identifier {
454                    *count += 1;
455                }
456
457                assert!(count <= required);
458                if count == required {
459                    (
460                        vec![TriggerConditionUpdate::Unsubscribe(
461                            counted_identifier.clone(),
462                        )],
463                        true,
464                        *count as f64,
465                    )
466                } else {
467                    (Default::default(), count >= required, *count as f64)
468                }
469            }
470            Self::Greater {
471                reference_event,
472                fulfilled,
473            } => Self::execute_cmp_event(
474                event,
475                reference_event,
476                fulfilled,
477                |ordering| matches!(ordering, Ordering::Greater),
478                Ordering::Greater,
479            ),
480            Self::GreaterOrEqual {
481                reference_event,
482                fulfilled,
483            } => Self::execute_cmp_event(
484                event,
485                reference_event,
486                fulfilled,
487                |ordering| matches!(ordering, Ordering::Greater | Ordering::Equal),
488                Ordering::Equal,
489            ),
490            Self::Equal {
491                reference_event,
492                fulfilled,
493            } => Self::execute_cmp_event(
494                event,
495                reference_event,
496                fulfilled,
497                |ordering| matches!(ordering, Ordering::Equal),
498                Ordering::Equal,
499            ),
500            Self::LessOrEqual {
501                reference_event,
502                fulfilled,
503            } => Self::execute_cmp_event(
504                event,
505                reference_event,
506                fulfilled,
507                |ordering| matches!(ordering, Ordering::Less | Ordering::Equal),
508                Ordering::Equal,
509            ),
510            Self::Less {
511                reference_event,
512                fulfilled,
513            } => Self::execute_cmp_event(
514                event,
515                reference_event,
516                fulfilled,
517                |ordering| matches!(ordering, Ordering::Less),
518                Ordering::Less,
519            ),
520            Self::Sequence {
521                current_index,
522                conditions,
523            } => {
524                assert!(*current_index < conditions.len());
525                let progress_base: f64 = conditions
526                    .iter()
527                    .take(*current_index)
528                    .map(|condition| condition.required_progress())
529                    .sum();
530                let (mut trigger_condition_update, result, current_progress) =
531                    conditions[*current_index].execute_event(event);
532                if result {
533                    let progress_base =
534                        progress_base + conditions[*current_index].required_progress();
535                    *current_index += 1;
536
537                    if *current_index < conditions.len() {
538                        trigger_condition_update.extend(
539                            conditions[*current_index]
540                                .subscriptions()
541                                .into_iter()
542                                .map(TriggerConditionUpdate::Subscribe),
543                        );
544                        (
545                            trigger_condition_update,
546                            false,
547                            progress_base + conditions[*current_index].current_progress(),
548                        )
549                    } else {
550                        (trigger_condition_update, true, progress_base)
551                    }
552                } else {
553                    (
554                        trigger_condition_update,
555                        false,
556                        progress_base + current_progress,
557                    )
558                }
559            }
560            Self::And {
561                conditions,
562                fulfilled_conditions,
563            } => {
564                assert!(!conditions.is_empty());
565                let mut trigger_condition_updates = Vec::new();
566                let mut current_progress: f64 = fulfilled_conditions
567                    .iter()
568                    .map(|condition| condition.required_progress())
569                    .sum();
570
571                // TODO replace with drain_filter once stable
572                let mut i = 0;
573                while i < conditions.len() {
574                    let (mut local_trigger_condition_updates, result, progress) =
575                        conditions[i].execute_event(event);
576                    trigger_condition_updates.append(&mut local_trigger_condition_updates);
577                    if result {
578                        current_progress += conditions[i].required_progress();
579                        fulfilled_conditions.push(conditions.remove(i));
580                    } else {
581                        current_progress += progress;
582                        i += 1;
583                    }
584                }
585                (
586                    trigger_condition_updates,
587                    conditions.is_empty(),
588                    current_progress,
589                )
590            }
591            Self::Or {
592                conditions,
593                fulfilled_conditions,
594            } => {
595                assert!(fulfilled_conditions.is_empty());
596                let mut trigger_condition_updates = Vec::new();
597                let mut current_progress: f64 = 0.0;
598
599                // TODO replace with drain_filter once stable
600                let mut i = 0;
601                while i < conditions.len() {
602                    let (mut local_trigger_condition_updates, result, progress) =
603                        conditions[i].execute_event(event);
604                    trigger_condition_updates.append(&mut local_trigger_condition_updates);
605                    if result {
606                        current_progress = 1.0;
607                        fulfilled_conditions.push(conditions.remove(i));
608                    } else {
609                        current_progress =
610                            current_progress.max(progress / conditions[i].required_progress());
611                        i += 1;
612                    }
613                }
614
615                let result = !fulfilled_conditions.is_empty();
616                if result {
617                    trigger_condition_updates.extend(conditions.iter().flat_map(|condition| {
618                        condition
619                            .subscriptions()
620                            .into_iter()
621                            .map(TriggerConditionUpdate::Unsubscribe)
622                    }));
623                }
624
625                (
626                    trigger_condition_updates,
627                    result,
628                    current_progress * self.required_progress(),
629                )
630            }
631            Self::AnyN {
632                conditions,
633                fulfilled_conditions,
634                n,
635            } => {
636                assert!(fulfilled_conditions.len() < *n);
637                let mut trigger_condition_updates = Vec::new();
638                let mut relative_progresses = vec![1.0; fulfilled_conditions.len()];
639
640                // TODO replace with drain_filter once stable
641                let mut i = 0;
642                while i < conditions.len() {
643                    let (mut local_trigger_condition_updates, result, progress) =
644                        conditions[i].execute_event(event);
645                    trigger_condition_updates.append(&mut local_trigger_condition_updates);
646                    if result {
647                        relative_progresses.push(1.0);
648                        fulfilled_conditions.push(conditions.remove(i));
649                    } else {
650                        relative_progresses.push(progress / conditions[i].required_progress());
651                        i += 1;
652                    }
653                }
654
655                let result = fulfilled_conditions.len() >= *n;
656                if result {
657                    trigger_condition_updates.extend(conditions.iter().flat_map(|condition| {
658                        condition
659                            .subscriptions()
660                            .into_iter()
661                            .map(TriggerConditionUpdate::Unsubscribe)
662                    }));
663                }
664
665                relative_progresses.sort_unstable_by(|a, b| a.partial_cmp(b).unwrap());
666                let current_progress = relative_progresses.iter().rev().take(*n).sum::<f64>()
667                    / (*n as f64)
668                    * self.required_progress();
669                (trigger_condition_updates, result, current_progress)
670            }
671        }
672    }
673
674    fn execute_cmp_event(
675        event: &Event,
676        reference_event: &Event,
677        fulfilled: &mut bool,
678        is_required_ordering: impl FnOnce(Ordering) -> bool,
679        closest_required_ordering: Ordering,
680    ) -> (Vec<TriggerConditionUpdate<Event::Identifier>>, bool, f64) {
681        assert!(!*fulfilled);
682        if is_required_ordering(event.partial_cmp(reference_event).unwrap()) {
683            *fulfilled = true;
684            return (
685                vec![TriggerConditionUpdate::Unsubscribe(
686                    reference_event.identifier(),
687                )],
688                true,
689                1.0,
690            );
691        }
692        (
693            vec![],
694            false,
695            event
696                .partial_cmp_progress(reference_event, closest_required_ordering)
697                .unwrap(),
698        )
699    }
700}