mcsr_ranked_api/types/
mod.rs1use std::{
2 collections::HashMap,
3 fmt::{self, Display},
4};
5
6use serde::{Deserialize, Deserializer, de};
7#[cfg(feature = "serialize")]
8use serde::{Serialize, ser::SerializeMap};
9use serde_json::Value;
10use uuid::Uuid;
11
12#[cfg(test)]
13mod tests;
14
15pub type Elo = u16;
16pub type EloChange = i16;
17pub type PhasePoints = u16;
18pub type Rank = u32;
19pub type Season = u8;
20pub type Phase = u8;
21#[cfg(feature = "matches")]
22pub type MatchId = u64;
23#[cfg(feature = "weekly_races")]
24pub type WeeklyRaceId = u32;
25pub type MinecraftSeed = u64;
26
27#[cfg_attr(feature = "serialize", derive(Serialize))]
28#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)]
29#[serde(transparent)]
30pub struct Time(pub u64);
31
32impl Time {
33 pub const fn new(value: u64) -> Self {
34 Self(value)
35 }
36 pub const fn millis(&self) -> u64 {
37 self.0 % 1000
38 }
39 pub const fn seconds(&self) -> u64 {
40 (self.0 / 1000) % 60
41 }
42 pub const fn minutes(&self) -> u64 {
43 (self.0 / 60000) % 60
44 }
45 pub const fn hours(&self) -> u64 {
46 self.0 / 3600000
47 }
48}
49
50#[doc(hidden)]
51pub type Result<T, E = Error> = std::result::Result<T, E>;
53
54#[doc(hidden)]
55#[derive(Debug)]
57pub enum Error {
58 Api(Value),
60 Reqwest(reqwest::Error),
62}
63
64impl PartialEq for Error {
65 fn eq(&self, other: &Self) -> bool {
66 match (self, other) {
67 (Error::Api(lhs), Error::Api(rhs)) => lhs == rhs,
68 (Error::Reqwest(lhs), Error::Reqwest(rhs)) => lhs.to_string() == rhs.to_string(),
69 _ => false,
70 }
71 }
72}
73impl Eq for Error {}
74
75impl From<reqwest::Error> for Error {
76 fn from(value: reqwest::Error) -> Self {
77 Self::Reqwest(value)
78 }
79}
80
81impl Display for Error {
82 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
83 match self {
84 Error::Api(api_err) => write!(f, "API Error: {api_err}"),
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(Value),
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(error) => Err(Error::Api(error)),
103 }
104 }
105}
106
107#[cfg_attr(feature = "serialize", derive(Serialize))]
109#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
110pub struct RankedAndCasual<T = u64> {
111 pub ranked: T,
112 pub casual: T,
113}
114
115#[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 pub fn user_1(&self) -> (Uuid, &T) {
126 (self.user_1_uuid, &self.user_1_data)
127 }
128 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}