mcsr_ranked_api/user/info/
mod.rs

1pub mod all_seasons;
2
3use chrono::serde::{ts_seconds, ts_seconds_option};
4use chrono::{DateTime, Utc};
5use serde::Deserialize;
6#[cfg(feature = "serialize")]
7use serde::Serialize;
8
9use super::UserProfile;
10#[cfg(feature = "achievements")]
11use crate::achievement::Achievement;
12use crate::types::{Elo, Phase, PhasePoints, Rank, RankedAndCasual};
13#[cfg(feature = "weekly_races")]
14use crate::weekly_race::result::WeeklyRaceResult;
15
16/// Displayed and total achievements of a user
17#[cfg(feature = "achievements")]
18#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
19#[cfg_attr(feature = "serialize", derive(Serialize))]
20#[serde(rename_all = "camelCase")]
21pub struct UserAchievements {
22	/// Achievements the user chose to display on their profile
23	pub display: Box<[Achievement]>,
24	/// All of the user's achievements
25	pub total: Box<[Achievement]>,
26}
27#[cfg(feature = "achievements")]
28impl UserAchievements {
29	/// Achievements the user chose to display on their profile
30	pub fn displayed(&self) -> &[Achievement] {
31		&self.display
32	}
33	/// All of the user's achievements
34	pub fn total(&self) -> &[Achievement] {
35		&self.total
36	}
37}
38
39#[cfg_attr(feature = "serialize", derive(Serialize))]
40#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
41#[serde(rename_all = "camelCase")]
42pub struct UserTimestamps {
43	#[serde(with = "ts_seconds")]
44	first_online: DateTime<Utc>,
45	#[serde(with = "ts_seconds")]
46	last_online: DateTime<Utc>,
47	#[serde(with = "ts_seconds")]
48	last_ranked: DateTime<Utc>,
49	#[serde(with = "ts_seconds_option")]
50	next_decay: Option<DateTime<Utc>>,
51}
52
53/// All of the user's statistics
54#[cfg_attr(feature = "serialize", derive(Serialize))]
55#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
56#[serde(rename_all = "camelCase")]
57pub struct UserStats {
58	pub best_time: RankedAndCasual<Option<u64>>,
59	pub highest_win_streak: RankedAndCasual,
60	pub current_win_streak: RankedAndCasual,
61	pub played_matches: RankedAndCasual,
62	pub playtime: RankedAndCasual,
63	pub completion_time: RankedAndCasual,
64	pub forfeits: RankedAndCasual,
65	pub completions: RankedAndCasual,
66	pub wins: RankedAndCasual,
67	#[serde(rename = "loses")]
68	pub losses: RankedAndCasual,
69}
70
71/// All statistics for season and total
72#[cfg_attr(feature = "serialize", derive(Serialize))]
73#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
74#[serde(rename_all = "camelCase")]
75pub struct UserStatistics {
76	pub season: UserStats,
77	pub total: UserStats,
78}
79
80/// User's social connection
81#[cfg_attr(feature = "serialize", derive(Serialize))]
82#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
83#[serde(rename_all = "camelCase")]
84pub struct UserConnection {
85	pub id: Box<str>,
86	pub name: Box<str>,
87}
88
89/// All of user's connections
90#[cfg_attr(feature = "serialize", derive(Serialize))]
91#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
92#[serde(rename_all = "camelCase")]
93pub struct UserConnections {
94	#[serde(default)]
95	pub discord: Option<UserConnection>,
96	#[serde(default)]
97	pub twitch: Option<UserConnection>,
98	#[serde(default)]
99	pub youtube: Option<UserConnection>,
100}
101
102#[cfg_attr(feature = "serialize", derive(Serialize))]
103#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
104#[serde(rename_all = "camelCase")]
105pub struct EloPointsInfo {
106	#[serde(rename = "eloRate")]
107	pub elo: Option<Elo>,
108	#[serde(rename = "eloRank")]
109	pub rank: Option<Rank>,
110	#[serde(alias = "phasePoint", alias = "point")]
111	pub points: PhasePoints,
112}
113
114#[cfg_attr(feature = "serialize", derive(Serialize))]
115#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
116#[serde(rename_all = "camelCase")]
117pub struct PhaseInfo {
118	pub phase: Phase,
119	#[serde(flatten)]
120	pub info: EloPointsInfo,
121}
122#[cfg(test)]
123impl PhaseInfo {
124	pub(crate) fn new(phase: Phase, elo: Elo, rank: Rank, points: PhasePoints) -> Self {
125		Self {
126			phase,
127			info: EloPointsInfo {
128				elo: Some(elo),
129				rank: Some(rank),
130				points,
131			},
132		}
133	}
134}
135
136/// Season result
137#[cfg_attr(feature = "serialize", derive(Serialize))]
138#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
139#[serde(rename_all = "camelCase")]
140pub struct UserSeasonOutcome {
141	pub last: EloPointsInfo,
142	pub highest: Option<Elo>,
143	pub lowest: Option<Elo>,
144	pub phases: Box<[PhaseInfo]>,
145}
146#[cfg(test)]
147impl UserSeasonOutcome {
148	pub(crate) fn new(
149		last_elo: Elo,
150		last_rank: Rank,
151		last_points: PhasePoints,
152		highest_elo: Elo,
153		lowest_elo: Elo,
154		phases: impl IntoIterator<Item = PhaseInfo>,
155	) -> Self {
156		Self {
157			last: EloPointsInfo {
158				elo: Some(last_elo),
159				rank: Some(last_rank),
160				points: last_points,
161			},
162			highest: Some(highest_elo),
163			lowest: Some(lowest_elo),
164			phases: phases.into_iter().collect(),
165		}
166	}
167}
168
169impl UserSeasonOutcome {
170	/// Every phase info
171	pub fn phases(&self) -> &[PhaseInfo] {
172		&self.phases
173	}
174}
175
176/// All of user's data combined
177#[cfg_attr(feature = "serialize", derive(Serialize))]
178#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
179#[serde(rename_all = "camelCase")]
180pub struct UserInfo {
181	#[serde(flatten)]
182	pub profile: UserProfile,
183	#[cfg(feature = "achievements")]
184	pub achievements: UserAchievements,
185	#[serde(rename = "timestamp")]
186	pub timestamps: UserTimestamps,
187	pub statistics: UserStatistics,
188	pub connections: UserConnections,
189	pub season_result: Option<UserSeasonOutcome>,
190	#[cfg(feature = "weekly_races")]
191	pub weekly_races: Box<[WeeklyRaceResult]>,
192}
193impl UserInfo {
194	/// User's weekly race stats
195	pub fn weekly_races(&self) -> &[WeeklyRaceResult] {
196		&self.weekly_races
197	}
198}