mcsr_ranked_api/types/
mod.rs1use 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)]
50pub type Result<T, E = Error> = std::result::Result<T, E>;
52
53#[doc(hidden)]
54#[derive(Debug)]
56pub enum Error {
57 Api(Option<Box<str>>),
59 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#[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#[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}