bloop_server_framework/evaluator/
mod.rs

1use crate::achievement::AchievementContext;
2use uuid::Uuid;
3
4pub(crate) mod boxed;
5pub mod min_bloops;
6pub mod registration_number;
7pub mod spelling_bee;
8pub mod streak;
9pub mod time;
10pub mod trigger;
11
12/// Result of evaluating whether an achievement should be awarded.
13#[derive(Debug, Clone, PartialEq, Eq)]
14pub enum EvalResult {
15    /// Award the achievement to the evaluating player only.
16    AwardSelf,
17    /// Award the achievement to multiple players, identified by UUIDs.
18    AwardMultiple(Vec<Uuid>),
19    /// Do not award the achievement.
20    NoAward,
21}
22
23impl From<bool> for EvalResult {
24    fn from(value: bool) -> Self {
25        if value {
26            EvalResult::AwardSelf
27        } else {
28            EvalResult::NoAward
29        }
30    }
31}
32
33impl From<Option<Uuid>> for EvalResult {
34    fn from(value: Option<Uuid>) -> Self {
35        value.map_or(EvalResult::NoAward, |value| {
36            EvalResult::AwardMultiple(vec![value])
37        })
38    }
39}
40
41impl From<Vec<Uuid>> for EvalResult {
42    fn from(value: Vec<Uuid>) -> Self {
43        Self::AwardMultiple(value)
44    }
45}
46
47impl From<Option<Vec<Uuid>>> for EvalResult {
48    fn from(value: Option<Vec<Uuid>>) -> Self {
49        value.map_or(EvalResult::NoAward, |value| {
50            EvalResult::AwardMultiple(value)
51        })
52    }
53}
54
55/// Trait for statically typed achievement evaluators.
56///
57/// This is the primary abstraction for writing custom logic to evaluate whether
58/// an achievement should be awarded.
59pub trait Evaluator<Player, State, Trigger> {
60    /// Evaluate the achievement for the given context.
61    fn evaluate(&self, ctx: &AchievementContext<Player, State, Trigger>) -> impl Into<EvalResult>;
62}
63
64#[cfg(test)]
65mod tests {
66    use super::*;
67    use uuid::Uuid;
68
69    #[test]
70    fn converts_bool_to_eval_result() {
71        assert_eq!(EvalResult::from(true), EvalResult::AwardSelf);
72        assert_eq!(EvalResult::from(false), EvalResult::NoAward);
73    }
74
75    #[test]
76    fn converts_option_uuid_to_eval_result() {
77        let uuid = Uuid::new_v4();
78        assert_eq!(
79            EvalResult::from(Some(uuid)),
80            EvalResult::AwardMultiple(vec![uuid])
81        );
82
83        assert_eq!(EvalResult::from(None::<Uuid>), EvalResult::NoAward);
84    }
85
86    #[test]
87    fn converts_vec_uuid_to_eval_result() {
88        let uuid1 = Uuid::new_v4();
89        let uuid2 = Uuid::new_v4();
90        let uuids = vec![uuid1, uuid2];
91
92        assert_eq!(
93            EvalResult::from(uuids.clone()),
94            EvalResult::AwardMultiple(uuids)
95        );
96    }
97
98    #[test]
99    fn converts_option_vec_uuid_to_eval_result() {
100        let uuid = Uuid::new_v4();
101
102        assert_eq!(
103            EvalResult::from(Some(vec![uuid])),
104            EvalResult::AwardMultiple(vec![uuid])
105        );
106
107        assert_eq!(
108            EvalResult::from(Some(vec![])),
109            EvalResult::AwardMultiple(vec![])
110        );
111
112        assert_eq!(EvalResult::from(None::<Vec<Uuid>>), EvalResult::NoAward);
113    }
114}