1pub mod battle;
5pub mod support;
6
7use crate::error::{Error, Result};
8use crate::player::PlayerId;
9use crate::round::RoundId;
10use battle::BattleReport;
11use itertools::Itertools;
12use jiff::Zoned;
13use serde::{Deserialize, Serialize};
14use std::collections::HashMap;
15use std::sync::Arc;
16use support::SupportReport;
17use uuid::Uuid;
18
19pub trait Report {
20 fn id(&self) -> ReportId;
21 fn round(&self) -> RoundId;
22 fn time(&self) -> &Zoned;
23}
24
25#[derive(Clone, Debug, Default, Deserialize, Serialize)]
26pub struct ReportManager {
27 reports: HashMap<ReportId, ReportKind>,
28 players: HashMap<PlayerId, Vec<ReportId>>,
29}
30
31impl ReportManager {
32 pub(crate) fn manage<I>(&mut self, report: ReportKind, players: I)
33 where
34 I: IntoIterator<Item = PlayerId>,
35 {
36 let id = report.as_dyn().id();
37 let players = players.into_iter().unique().collect_vec();
38
39 if !players.is_empty() {
40 for player in players {
41 self
42 .players
43 .entry(player)
44 .or_default()
45 .push(id);
46 }
47
48 debug_assert!(!self.reports.contains_key(&id));
49 self.reports.insert(id, report);
50 }
51 }
52
53 pub fn report(&self, id: ReportId) -> Result<&ReportKind> {
54 self
55 .reports
56 .get(&id)
57 .ok_or(Error::ReportNotFound(id))
58 }
59
60 pub fn reports_by<F>(&self, f: F) -> impl Iterator<Item = &ReportKind>
61 where
62 F: Fn((ReportId, &ReportKind)) -> bool,
63 {
64 self
65 .reports
66 .iter()
67 .filter(move |(id, report)| f((**id, report)))
68 .map(|(_, report)| report)
69 }
70
71 pub fn reports_of(&self, player: &PlayerId) -> impl Iterator<Item = ReportId> {
72 self
73 .players
74 .get(player)
75 .map(Vec::as_slice)
76 .unwrap_or_default()
77 .iter()
78 .copied()
79 }
80}
81
82#[derive(Clone, Debug, Deserialize, Serialize)]
83#[serde(tag = "kind", rename_all = "kebab-case")]
84#[remain::sorted]
85pub enum ReportKind {
86 Battle { report: Arc<BattleReport> },
87 Support { report: Arc<SupportReport> },
88}
89
90impl ReportKind {
91 pub fn as_dyn(&self) -> &dyn Report {
92 match self {
93 Self::Battle { report } => report.as_ref(),
94 Self::Support { report } => report.as_ref(),
95 }
96 }
97}
98
99#[must_use]
100#[derive(
101 Clone,
102 Copy,
103 Debug,
104 derive_more::Display,
105 PartialEq,
106 Eq,
107 PartialOrd,
108 Ord,
109 Hash,
110 Deserialize,
111 Serialize,
112)]
113pub struct ReportId(Uuid);
114
115impl ReportId {
116 #[inline]
117 pub fn new() -> Self {
118 Self(Uuid::now_v7())
119 }
120}
121
122impl Default for ReportId {
123 fn default() -> Self {
124 Self::new()
125 }
126}