Skip to main content

wowlab_analytics/analytics/merge/
keys.rs

1use wowlab_types::proto;
2
3/// Enum fields stay raw discriminants so unknown protobuf values keep a distinct identity.
4#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
5pub(super) struct ActionKey {
6    spell_id: u32,
7    target_id: u32,
8    source: i32,
9    source_kind: i32,
10    source_id: u32,
11    pull_id: Option<u32>,
12    group_id: Option<u32>,
13}
14
15impl From<&proto::ActionRow> for ActionKey {
16    fn from(row: &proto::ActionRow) -> Self {
17        Self {
18            spell_id: row.spell_id,
19            target_id: row.target_id,
20            source: row.source,
21            source_kind: row.source_kind,
22            source_id: row.source_id,
23            pull_id: row.pull_id,
24            group_id: row.group_id,
25        }
26    }
27}
28
29/// Field order matches the emitted-row contract (drives `Ord`); hash identity is order-independent.
30#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
31pub(super) struct AuraKey {
32    aura_id: u32,
33    target_id: u32,
34    affected_kind: i32,
35    affected_id: u32,
36    source_kind: i32,
37    source_id: u32,
38    pull_id: Option<u32>,
39    group_id: Option<u32>,
40}
41
42impl From<&proto::AuraRow> for AuraKey {
43    fn from(row: &proto::AuraRow) -> Self {
44        Self {
45            aura_id: row.aura_id,
46            target_id: row.target_id,
47            affected_kind: row.affected_kind,
48            affected_id: row.affected_id,
49            source_kind: row.source_kind,
50            source_id: row.source_id,
51            pull_id: row.pull_id,
52            group_id: row.group_id,
53        }
54    }
55}
56
57#[cfg(test)]
58mod tests {
59    use googletest::prelude::*;
60
61    use super::*;
62
63    #[gtest]
64    fn action_key_retains_known_and_unknown_discriminants() -> Result<()> {
65        let known = proto::ActionRow {
66            source: proto::ActionSource::Player as i32,
67            source_kind: proto::ActorKind::Player as i32,
68            ..Default::default()
69        };
70        let unknown = proto::ActionRow {
71            source: i32::MAX,
72            source_kind: i32::MIN,
73            ..known
74        };
75
76        verify_that!(ActionKey::from(&known), not(eq(ActionKey::from(&unknown))))?;
77
78        verify_that!(ActionKey::from(&unknown), eq(ActionKey::from(&unknown)))
79    }
80
81    #[gtest]
82    fn aura_key_order_matches_the_emitted_row_contract() -> Result<()> {
83        let affected_first = proto::AuraRow {
84            aura_id: 1,
85            target_id: 2,
86            affected_kind: 3,
87            affected_id: 4,
88            source_kind: 20,
89            source_id: 30,
90            ..Default::default()
91        };
92        let source_first = proto::AuraRow {
93            affected_kind: 4,
94            source_kind: 1,
95            ..affected_first
96        };
97
98        verify_that!(
99            AuraKey::from(&affected_first),
100            lt(AuraKey::from(&source_first))
101        )
102    }
103}