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