1use chrono::{DateTime, FixedOffset};
4use serde::{Deserialize, Serialize};
5
6use crate::model::gateway::activity::Activity;
7use crate::model::id::{GuildId, RoleId, ToSnowflakeId, UserId};
8use crate::model::user::User;
9
10#[derive(Clone, Debug, Deserialize, Serialize)]
12#[serde(untagged)]
13pub enum PartialUser {
14 Full(User),
16 #[non_exhaustive]
18 Partial {
19 id: UserId,
21 },
22}
23
24impl crate::model::id::private::Sealed for PartialUser {}
25
26impl ToSnowflakeId for PartialUser {
27 type Id = UserId;
28
29 fn id(&self) -> Self::Id {
30 match self {
31 PartialUser::Full(user) => user.id,
32 PartialUser::Partial { id } => *id,
33 }
34 }
35}
36
37#[derive(Clone, Copy, Debug, Eq, PartialEq, Deserialize, Serialize)]
42pub enum OnlineStatus {
43 #[serde(rename = "idle")]
45 Idle,
46 #[serde(rename = "dnd")]
48 DoNotDisturb,
49 #[serde(rename = "online")]
51 Online,
52 #[serde(rename = "offline")]
54 Offline,
55}
56
57impl OnlineStatus {
58 #[allow(clippy::trivially_copy_pass_by_ref)]
60 #[inline]
61 fn is_offline(&self) -> bool {
62 match self {
63 OnlineStatus::Offline => true,
64 _ => false,
65 }
66 }
67}
68
69impl Default for OnlineStatus {
70 fn default() -> Self {
71 OnlineStatus::Offline
72 }
73}
74
75#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
79pub struct ClientStatus {
80 #[serde(default, skip_serializing_if = "OnlineStatus::is_offline")]
83 pub desktop: OnlineStatus,
84 #[serde(default, skip_serializing_if = "OnlineStatus::is_offline")]
86 pub mobile: OnlineStatus,
87 #[serde(default, skip_serializing_if = "OnlineStatus::is_offline")]
90 pub web: OnlineStatus,
91}
92
93#[derive(Clone, Debug, Deserialize, Serialize)]
98pub struct Presence {
99 pub user: PartialUser,
101 pub roles: Vec<RoleId>,
103 pub game: Option<Activity>,
105 pub guild_id: GuildId,
107 pub status: OnlineStatus,
109 pub activities: Vec<Activity>,
111 pub client_status: ClientStatus,
113 #[serde(default, skip_serializing_if = "Option::is_none")]
115 pub premium_since: Option<DateTime<FixedOffset>>,
116 #[serde(default, skip_serializing_if = "Option::is_none")]
118 pub nick: Option<String>,
119}
120
121impl crate::model::id::private::Sealed for Presence {}
122
123impl ToSnowflakeId for Presence {
124 type Id = <PartialUser as ToSnowflakeId>::Id;
125
126 fn id(&self) -> Self::Id {
127 self.user.id()
128 }
129}
130
131impl_eq_fields!(PartialUser: (a, b) => {
132 match (a, b) {
133 (PartialUser::Full(a), PartialUser::Full(b)) => assert_eq_fields!(a, b),
134 (PartialUser::Partial { id: id_a }, PartialUser::Partial { id: id_b }) => assert_eq_fields!(id_a, id_b),
135 (a, b) => panic_ne_fields!(a, b),
136 }
137});
138impl_eq_fields!(Presence: [
139 user,
140 roles,
141 game,
142 guild_id,
143 status,
144 activities,
145 client_status,
146 premium_since,
147 nick
148]);
149
150#[cfg(test)]
151mod tests {
152 use serde_json::json;
153
154 use crate::model::user::Discriminator;
155
156 use super::*;
157
158 #[test]
159 fn test_deserialize_partial_user() {
160 let value = json!({
161 "id": "80351110224678912"
162 });
163 let user = PartialUser::Partial {
164 id: UserId::from(80351110224678912),
165 };
166
167 let deserialized = PartialUser::deserialize(&value).unwrap();
168 assert_eq_fields!(user, deserialized);
169 }
170
171 #[test]
172 fn test_serialize_partial_user() {
173 let value = json!({
174 "id": "80351110224678912"
175 });
176 let user = PartialUser::Partial {
177 id: UserId::from(80351110224678912),
178 };
179
180 assert_eq!(value, serde_json::to_value(&user).unwrap());
181 }
182
183 #[test]
184 fn test_deserialize_full_user() {
185 let value = json!({
186 "id": "80351110224678912",
187 "username": "Nelly",
188 "discriminator": "1337",
189 "avatar": "8342729096ea3675442027381ff50dfe",
190 });
191 let user = PartialUser::Full(User {
192 id: UserId::from(80351110224678912),
193 name: "Nelly".to_owned(),
194 discriminator: Discriminator::new(1337).unwrap(),
195 avatar: Some("8342729096ea3675442027381ff50dfe".to_owned()),
196 bot: false,
197 system: false,
198 });
199
200 let deserialized = PartialUser::deserialize(&value).unwrap();
201 assert_eq_fields!(user, deserialized);
202 }
203
204 #[test]
205 fn test_serialize_full_user() {
206 let value = json!({
207 "id": "80351110224678912",
208 "username": "Nelly",
209 "discriminator": "1337",
210 "avatar": "8342729096ea3675442027381ff50dfe"
211 });
212 let user = PartialUser::Full(User {
213 id: UserId::from(80351110224678912),
214 name: "Nelly".to_owned(),
215 discriminator: Discriminator::new(1337).unwrap(),
216 avatar: Some("8342729096ea3675442027381ff50dfe".to_owned()),
217 bot: false,
218 system: false,
219 });
220
221 assert_eq!(value, serde_json::to_value(&user).unwrap());
222 }
223}