Skip to main content

patterns/
awards.rs

1use patterns_macros::because;
2use std::collections::{BTreeMap, BTreeSet};
3
4#[derive(patterns_macros::Record)]
5#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
6pub struct Award {
7    pub count: u64,
8    pub first: u64,
9    pub last: u64,
10}
11because!(Award, "how many have earned one badge and when the first and the last did, the row a badge's leaderboard reads");
12
13#[derive(patterns_macros::Record)]
14#[derive(Clone, Debug, PartialEq, Eq)]
15pub struct Earned<K, A> {
16    pub who: K,
17    pub badge: A,
18    pub at: u64,
19    pub rank: u64,
20}
21because!(Earned, "one account earning one badge at a moment, ranked by how many had earned it before, the row an account page lists");
22
23pub type Given<K, A> = BTreeSet<(K, A)>;
24because!(Given, "who has already been given which award, kept as a set of pairs so the question a grant asks, whether this one has had this already, is the set own membership test");
25
26pub type Awards<A> = BTreeMap<A, Award>;
27because!(Awards, "how many of each award have been given and when the first and last went out, which is what a rank is counted from");
28
29pub type Granted<K, A> = (Given<K, A>, Awards<A>, Vec<Earned<K, A>>);
30because!(Granted, "what a round of granting leaves behind: the pairs now given, the counts now raised, and the rows the round produced, returned together because a caller that took one and not the others would be holding a record of a grant that never happened");
31
32pub fn awarded<K: Ord + Clone, A: Ord + Copy>(given: Given<K, A>, awards: Awards<A>, candidates: &[(K, A)], at: u64) -> Granted<K, A> {
33    let mut given = given;
34    let mut awards = awards;
35    let mut rows = Vec::new();
36    for (who, badge) in candidates {
37        if !given.insert((who.clone(), *badge)) {
38            continue;
39        }
40        let award = awards.entry(*badge).or_default();
41        award.count += 1;
42        if award.first == 0 {
43            award.first = at;
44        }
45        award.last = award.last.max(at);
46        rows.push(Earned {
47            who: who.clone(),
48            badge: *badge,
49            at,
50            rank: award.count,
51        });
52    }
53    (given, awards, rows)
54}
55because!(awarded, "candidates granted once each and never again, each taking the next rank of its badge, in the order offered, so a badge earned twice in one batch counts once and the rank an account keeps is the one it earned at the time");