rosu_v2/request/
ranking.rs

1use crate::{
2    model::{
3        ranking::{ChartRankings, CountryRankings, RankingType, Rankings, Spotlight},
4        user::CountryCode,
5        DeserializedList, GameMode,
6    },
7    prelude::TeamRankings,
8    request::{Query, Request},
9    routing::Route,
10    Osu,
11};
12
13use serde::Serialize;
14
15/// Get a [`ChartRankings`] struct containing a [`Spotlight`], its
16/// [`BeatmapsetExtended`]s, and participating [`User`]s.
17///
18/// The mapset will have their `maps` option filled.
19///
20/// The user statistics contain specific, spotlight related data.
21/// All fields depends only on scores on maps of the spotlight.
22/// The statistics vector is ordered by `ranked_score`.
23/// The `user` option is filled.
24///
25/// [`BeatmapsetExtended`]: crate::model::beatmap::BeatmapsetExtended
26/// [`User`]: crate::model::user::User
27#[must_use = "requests must be configured and executed"]
28#[derive(Serialize)]
29pub struct GetChartRankings<'a> {
30    #[serde(skip)]
31    osu: &'a Osu,
32    #[serde(skip)]
33    mode: GameMode,
34    spotlight: Option<u32>,
35}
36
37impl<'a> GetChartRankings<'a> {
38    pub(crate) const fn new(osu: &'a Osu, mode: GameMode) -> Self {
39        Self {
40            osu,
41            mode,
42            spotlight: None,
43        }
44    }
45
46    /// Specify the spotlight id. If none is given,
47    /// the latest spotlight will be returned.
48    #[inline]
49    pub const fn spotlight(mut self, spotlight_id: u32) -> Self {
50        self.spotlight = Some(spotlight_id);
51
52        self
53    }
54}
55
56into_future! {
57    |self: GetChartRankings<'_>| -> ChartRankings {
58        Request::with_query(
59            Route::GetRankings {
60                mode: self.mode,
61                ranking_type: RankingType::Charts,
62            },
63            Query::encode(&self),
64        )
65    }
66}
67
68/// Get a [`CountryRankings`] struct containing a vec of [`CountryRanking`]s
69/// which will be sorted by the country's total pp.
70///
71/// [`CountryRanking`]: crate::model::ranking::CountryRanking
72#[must_use = "requests must be configured and executed"]
73#[derive(Serialize)]
74pub struct GetCountryRankings<'a> {
75    #[serde(skip)]
76    osu: &'a Osu,
77    #[serde(skip)]
78    mode: GameMode,
79    #[serde(rename(serialize = "cursor[page]"))]
80    page: Option<u32>,
81}
82
83impl<'a> GetCountryRankings<'a> {
84    pub(crate) const fn new(osu: &'a Osu, mode: GameMode) -> Self {
85        Self {
86            osu,
87            mode,
88            page: None,
89        }
90    }
91
92    /// Specify a page
93    #[inline]
94    pub const fn page(mut self, page: u32) -> Self {
95        self.page = Some(page);
96
97        self
98    }
99}
100
101into_future! {
102    |self: GetCountryRankings<'_>| -> CountryRankings {
103        Request::with_query(
104            Route::GetRankings {
105                mode: self.mode,
106                ranking_type: RankingType::Country,
107            },
108            Query::encode(&self),
109        )
110    }
111}
112
113/// Get a [`Rankings`] struct whose [`User`]s are sorted by their pp, i.e. the
114/// current pp leaderboard.
115///
116/// [`User`]: crate::model::user::User
117#[must_use = "requests must be configured and executed"]
118#[derive(Serialize)]
119pub struct GetPerformanceRankings<'a> {
120    #[serde(skip)]
121    osu: &'a Osu,
122    #[serde(skip)]
123    mode: GameMode,
124    country: Option<CountryCode>,
125    variant: Option<&'static str>,
126    #[serde(rename(serialize = "cursor[page]"))]
127    page: Option<u32>,
128}
129
130impl<'a> GetPerformanceRankings<'a> {
131    pub(crate) const fn new(osu: &'a Osu, mode: GameMode) -> Self {
132        Self {
133            osu,
134            mode,
135            country: None,
136            variant: None,
137            page: None,
138        }
139    }
140
141    /// Specify a country code.
142    #[inline]
143    pub fn country(mut self, country: impl Into<CountryCode>) -> Self {
144        self.country = Some(country.into());
145
146        self
147    }
148
149    /// Consider only 4K scores. Only relevant for osu!mania.
150    #[inline]
151    pub const fn variant_4k(mut self) -> Self {
152        self.variant = Some("4k");
153
154        self
155    }
156
157    /// Consider only 7K scores. Only relevant for osu!mania.
158    #[inline]
159    pub const fn variant_7k(mut self) -> Self {
160        self.variant = Some("7k");
161
162        self
163    }
164
165    /// Pages range from 1 to 200.
166    #[inline]
167    pub const fn page(mut self, page: u32) -> Self {
168        self.page = Some(page);
169
170        self
171    }
172}
173
174into_future! {
175    |self: GetPerformanceRankings<'_>| -> Rankings {
176        let req = Request::with_query(
177            Route::GetRankings {
178                mode: self.mode,
179                ranking_type: RankingType::Performance,
180            },
181            Query::encode(&self),
182        );
183
184        (req, self.mode)
185    } => |rankings, mode: GameMode| -> Rankings {
186        rankings.mode = Some(mode);
187        rankings.ranking_type = Some(RankingType::Performance);
188
189        Ok(rankings)
190    }
191}
192
193/// Get a [`Rankings`] struct whose [`User`]s are sorted by their ranked score,
194/// i.e. the current ranked score leaderboard.
195///
196/// [`User`]: crate::model::user::User
197#[must_use = "requests must be configured and executed"]
198#[derive(Serialize)]
199pub struct GetScoreRankings<'a> {
200    #[serde(skip)]
201    osu: &'a Osu,
202    #[serde(skip)]
203    mode: GameMode,
204    #[serde(rename(serialize = "cursor[page]"))]
205    page: Option<u32>,
206}
207
208impl<'a> GetScoreRankings<'a> {
209    pub(crate) const fn new(osu: &'a Osu, mode: GameMode) -> Self {
210        Self {
211            osu,
212            mode,
213            page: None,
214        }
215    }
216
217    /// Pages range from 1 to 200.
218    #[inline]
219    pub const fn page(mut self, page: u32) -> Self {
220        self.page = Some(page);
221
222        self
223    }
224}
225
226into_future! {
227    |self: GetScoreRankings<'_>| -> Rankings {
228        let req = Request::with_query(
229            Route::GetRankings {
230                mode: self.mode,
231                ranking_type: RankingType::Score,
232            },
233            Query::encode(&self)
234        );
235
236        (req, self.mode)
237    } => |rankings, mode: GameMode| -> Rankings {
238        rankings.mode = Some(mode);
239        rankings.ranking_type = Some(RankingType::Score);
240
241        Ok(rankings)
242    }
243}
244
245/// Get a vec of [`Spotlight`]s.
246#[must_use = "requests must be configured and executed"]
247pub struct GetSpotlights<'a> {
248    osu: &'a Osu,
249}
250
251impl<'a> GetSpotlights<'a> {
252    pub(crate) const fn new(osu: &'a Osu) -> Self {
253        Self { osu }
254    }
255}
256
257into_future! {
258    |self: GetSpotlights<'_>| -> DeserializedList<Spotlight> {
259        Request::new(Route::GetSpotlights)
260    } => |spotlights, _| -> Vec<Spotlight> {
261        Ok(spotlights.0)
262    }
263}
264
265/// Get a [`TeamRankings`] struct whose entries are sorted by their pp.
266#[must_use = "requests must be configured and executed"]
267#[derive(Serialize)]
268pub struct GetTeamRankings<'a> {
269    #[serde(skip)]
270    osu: &'a Osu,
271    #[serde(skip)]
272    mode: GameMode,
273    #[serde(rename(serialize = "cursor[page]"))]
274    page: Option<u32>,
275}
276
277impl<'a> GetTeamRankings<'a> {
278    pub(crate) const fn new(osu: &'a Osu, mode: GameMode) -> Self {
279        Self {
280            osu,
281            mode,
282            page: None,
283        }
284    }
285
286    /// Pages range from 1 to 200.
287    #[inline]
288    pub const fn page(mut self, page: u32) -> Self {
289        self.page = Some(page);
290
291        self
292    }
293}
294
295into_future! {
296    |self: GetTeamRankings<'_>| -> TeamRankings {
297        let req = Request::with_query(
298            Route::GetRankings {
299                mode: self.mode,
300                ranking_type: RankingType::Team,
301            },
302            Query::encode(&self),
303        );
304
305        (req, self.mode)
306    } => |rankings, mode: GameMode| -> TeamRankings {
307        rankings.mode = Some(mode);
308
309        Ok(rankings)
310    }
311}