1use strum::{Display, EnumIter, EnumString, IntoEnumIterator};
2
3// An integer indicating a type of notification. The variants' numerical
4// values are stored in the database, so they should never be removed
5// or changed.
6#[repr(i32)]
7#[derive(Copy, Clone, Debug, EnumIter, EnumString, Display)]
8pub enum NotificationKind {
9 ContactRequest = 0,
10 ChannelInvitation = 1,
11 ChannelMessageMention = 2,
12}
13
14pub enum Notification {
15 ContactRequest {
16 requester_id: u64,
17 },
18 ChannelInvitation {
19 inviter_id: u64,
20 channel_id: u64,
21 },
22 ChannelMessageMention {
23 sender_id: u64,
24 channel_id: u64,
25 message_id: u64,
26 },
27}
28
29#[derive(Copy, Clone)]
30pub enum NotificationEntityKind {
31 User,
32 Channel,
33 ChannelMessage,
34}
35
36impl Notification {
37 /// Load this notification from its generic representation, which is
38 /// used to represent it in the database, and in the wire protocol.
39 ///
40 /// The order in which a given notification type's fields are listed must
41 /// match the order they're listed in the `to_parts` method, and it must
42 /// not change, because they're stored in that order in the database.
43 pub fn from_parts(kind: NotificationKind, entity_ids: [Option<u64>; 3]) -> Option<Self> {
44 use NotificationKind::*;
45
46 Some(match kind {
47 ContactRequest => Self::ContactRequest {
48 requester_id: entity_ids[0]?,
49 },
50 ChannelInvitation => Self::ChannelInvitation {
51 inviter_id: entity_ids[0]?,
52 channel_id: entity_ids[1]?,
53 },
54 ChannelMessageMention => Self::ChannelMessageMention {
55 sender_id: entity_ids[0]?,
56 channel_id: entity_ids[1]?,
57 message_id: entity_ids[2]?,
58 },
59 })
60 }
61
62 /// Convert this notification into its generic representation, which is
63 /// used to represent it in the database, and in the wire protocol.
64 ///
65 /// The order in which a given notification type's fields are listed must
66 /// match the order they're listed in the `from_parts` method, and it must
67 /// not change, because they're stored in that order in the database.
68 ///
69 /// Along with each field, provide the kind of entity that the field refers
70 /// to. This is used to load the associated entities for a batch of
71 /// notifications from the database.
72 pub fn to_parts(&self) -> (NotificationKind, [Option<(u64, NotificationEntityKind)>; 3]) {
73 use NotificationKind::*;
74
75 match self {
76 Self::ContactRequest { requester_id } => (
77 ContactRequest,
78 [
79 Some((*requester_id, NotificationEntityKind::User)),
80 None,
81 None,
82 ],
83 ),
84
85 Self::ChannelInvitation {
86 inviter_id,
87 channel_id,
88 } => (
89 ChannelInvitation,
90 [
91 Some((*inviter_id, NotificationEntityKind::User)),
92 Some((*channel_id, NotificationEntityKind::User)),
93 None,
94 ],
95 ),
96
97 Self::ChannelMessageMention {
98 sender_id,
99 channel_id,
100 message_id,
101 } => (
102 ChannelMessageMention,
103 [
104 Some((*sender_id, NotificationEntityKind::User)),
105 Some((*channel_id, NotificationEntityKind::ChannelMessage)),
106 Some((*message_id, NotificationEntityKind::Channel)),
107 ],
108 ),
109 }
110 }
111}
112
113impl NotificationKind {
114 pub fn all() -> impl Iterator<Item = Self> {
115 Self::iter()
116 }
117
118 pub fn from_i32(i: i32) -> Option<Self> {
119 Self::iter().find(|kind| *kind as i32 == i)
120 }
121}