1use std::cmp::Ordering;
2
3use crate::triggers::TriggerEvent;
4#[cfg(feature = "serde")]
5use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, Eq, PartialEq)]
11pub enum TriggerCondition<Event> {
12 None,
14
15 Never,
17
18 EventCount {
20 event: Event,
22 required: usize,
24 },
25
26 Greater {
28 reference_event: Event,
30 },
31
32 GreaterOrEqual {
34 reference_event: Event,
36 },
37
38 Equal {
40 reference_event: Event,
42 },
43
44 LessOrEqual {
46 reference_event: Event,
48 },
49
50 Less {
52 reference_event: Event,
54 },
55
56 Sequence {
62 conditions: Vec<TriggerCondition<Event>>,
64 },
65
66 And {
80 conditions: Vec<TriggerCondition<Event>>,
82 },
83
84 Or {
96 conditions: Vec<TriggerCondition<Event>>,
98 },
99
100 AnyN {
102 conditions: Vec<TriggerCondition<Event>>,
104 n: usize,
106 },
107}
108
109#[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 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 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 pub fn required_progress(&self) -> f64 {
301 self.required_progress
302 }
303
304 pub fn current_progress(&self) -> f64 {
306 assert!(self.current_progress.is_finite());
307 self.current_progress
308 }
309
310 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 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 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 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}