mcsr_ranked_api/types/
mod.rs

1use std::{
2	collections::HashMap,
3	fmt::{self, Display},
4};
5
6use serde::{de, Deserialize, Deserializer};
7#[cfg(feature = "serialize")]
8use serde::{ser::SerializeMap, Serialize};
9use uuid::Uuid;
10
11#[cfg(test)]
12mod tests;
13
14pub type Elo = u16;
15pub type EloChange = i16;
16pub type PhasePoints = u16;
17pub type Rank = u32;
18pub type Season = u8;
19pub type Phase = u8;
20#[cfg(feature = "matches")]
21pub type MatchId = u64;
22#[cfg(feature = "weekly_races")]
23pub type WeeklyRaceId = u32;
24pub type MinecraftSeed = u64;
25
26#[cfg_attr(feature = "serialize", derive(Serialize))]
27#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)]
28#[serde(transparent)]
29pub struct Time(pub u64);
30
31impl Time {
32	pub const fn new(value: u64) -> Self {
33		Self(value)
34	}
35	pub const fn millis(&self) -> u64 {
36		self.0 % 1000
37	}
38	pub const fn seconds(&self) -> u64 {
39		(self.0 / 1000) % 60
40	}
41	pub const fn minutes(&self) -> u64 {
42		(self.0 / 60000) % 60
43	}
44	pub const fn hours(&self) -> u64 {
45		self.0 / 3600000
46	}
47}
48
49#[doc(hidden)]
50/// Result with this crate's own `Error` type as default
51pub type Result<T, E = Error> = std::result::Result<T, E>;
52
53#[doc(hidden)]
54/// Error returned by a request to the API
55#[derive(Debug)]
56pub enum Error {
57	/// Ranked API error
58	Api(Option<Box<str>>),
59	/// Reqwest library error
60	Reqwest(reqwest::Error),
61}
62
63impl PartialEq for Error {
64	fn eq(&self, other: &Self) -> bool {
65		match (self, other) {
66			(Error::Api(lhs), Error::Api(rhs)) => lhs == rhs,
67			(Error::Reqwest(lhs), Error::Reqwest(rhs)) => lhs.to_string() == rhs.to_string(),
68			_ => false,
69		}
70	}
71}
72impl Eq for Error {}
73
74impl From<reqwest::Error> for Error {
75	fn from(value: reqwest::Error) -> Self {
76		Self::Reqwest(value)
77	}
78}
79
80impl Display for Error {
81	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82		match self {
83			Error::Api(Some(api_err)) => write!(f, "API Error: {}", api_err),
84			Error::Api(None) => f.write_str("API Error! (No message)"),
85			Error::Reqwest(req_err) => write!(f, "Reqwest Error: {}", req_err),
86		}
87	}
88}
89impl std::error::Error for Error {}
90
91#[derive(Debug, PartialEq, Eq, Deserialize)]
92#[serde(tag = "status", content = "data", rename_all = "camelCase")]
93pub(crate) enum DeResult<T> {
94	Success(T),
95	Error(Option<Box<str>>),
96}
97
98impl<T> From<DeResult<T>> for Result<T> {
99	fn from(value: DeResult<T>) -> Self {
100		match value {
101			DeResult::Success(t) => Ok(t),
102			DeResult::Error(e) => Err(Error::Api(e)),
103		}
104	}
105}
106
107/// Container for ranked and casual values
108#[cfg_attr(feature = "serialize", derive(Serialize))]
109#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
110pub struct RankedAndCasual<T> {
111	pub ranked: T,
112	pub casual: T,
113}
114
115/// Container for UUIDs and data of exactly two players
116#[derive(Debug, Clone, Copy, PartialEq, Eq)]
117pub struct TwoUserData<T> {
118	pub user_1_uuid: Uuid,
119	pub user_1_data: T,
120	pub user_2_uuid: Uuid,
121	pub user_2_data: T,
122}
123impl<T> TwoUserData<T> {
124	/// First user's UUID and data
125	pub fn user_1(&self) -> (Uuid, &T) {
126		(self.user_1_uuid, &self.user_1_data)
127	}
128	/// Second user's UUID and data
129	pub fn user_2(&self) -> (Uuid, &T) {
130		(self.user_2_uuid, &self.user_2_data)
131	}
132}
133
134impl<'de, T: Deserialize<'de>> Deserialize<'de> for TwoUserData<T> {
135	fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
136	where
137		D: Deserializer<'de>,
138	{
139		let mut entries = HashMap::<Uuid, T>::deserialize(deserializer)?
140			.into_iter()
141			.collect::<Vec<_>>();
142		entries.sort_by_key(|(uuid, _)| *uuid);
143		let [(user_1_uuid, user_1_data), (user_2_uuid, user_2_data)] = entries
144			.try_into()
145			.map_err(|err: Vec<_>| de::Error::invalid_length(err.len(), &"2"))?;
146		Ok(TwoUserData {
147			user_1_uuid,
148			user_1_data,
149			user_2_uuid,
150			user_2_data,
151		})
152	}
153}
154#[cfg(feature = "serialize")]
155impl<T: Serialize> Serialize for TwoUserData<T> {
156	fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
157	where
158		S: serde::Serializer,
159	{
160		let mut map = serializer.serialize_map(Some(2))?;
161		map.serialize_entry(&self.user_1_uuid, &self.user_1_data)?;
162		map.serialize_entry(&self.user_2_uuid, &self.user_2_data)?;
163		map.end()
164	}
165}