Skip to main content

rosu_render/request/
render_list.rs

1use std::future::IntoFuture;
2
3use serde::Serialize;
4
5use crate::{model::RenderList, routing::Route, ClientError, OrdrClient};
6
7use super::{OrdrFuture, Request, RequestBuilder};
8
9#[derive(Serialize)]
10struct GetRenderListFields<'a> {
11    #[serde(rename = "pageSize")]
12    page_size: Option<u32>,
13    page: Option<u32>,
14    #[serde(rename = "ordrUsername")]
15    ordr_username: Option<&'a str>,
16    #[serde(rename = "replayUsername")]
17    replay_username: Option<&'a str>,
18    #[serde(rename = "renderID")]
19    render_id: Option<u32>,
20    #[serde(rename = "nobots")]
21    no_bots: Option<bool>,
22    link: Option<&'a str>,
23    #[serde(rename = "beatmapsetid")]
24    mapset_id: Option<u32>,
25}
26
27/// Get a [`RenderList`].
28#[must_use]
29pub struct GetRenderList<'a> {
30    ordr: &'a OrdrClient,
31    fields: GetRenderListFields<'a>,
32}
33
34impl<'a> GetRenderList<'a> {
35    pub(crate) const fn new(ordr: &'a OrdrClient) -> Self {
36        Self {
37            ordr,
38            fields: GetRenderListFields {
39                page_size: None,
40                page: None,
41                ordr_username: None,
42                replay_username: None,
43                render_id: None,
44                no_bots: None,
45                link: None,
46                mapset_id: None,
47            },
48        }
49    }
50
51    /// The number of renders the query will return you in the page. If not specified, 50 is the default.
52    pub fn page_size(&mut self, page_size: u32) -> &mut Self {
53        self.fields.page_size = Some(page_size);
54        self.fields.page.get_or_insert(1);
55
56        self
57    }
58
59    /// The page.
60    pub fn page(&mut self, page: u32) -> &mut Self {
61        self.fields.page = Some(page);
62
63        self
64    }
65
66    /// Search by o!rdr username, can be used at the same time as [`replay_username`].
67    ///
68    /// [`replay_username`]: GetRenderList::replay_username
69    pub fn ordr_username(&mut self, ordr_username: &'a str) -> &mut Self {
70        self.fields.ordr_username = Some(ordr_username);
71
72        self
73    }
74
75    /// Search by replay username, can be used at the same time as [`ordr_username`].
76    ///
77    /// [`ordr_username`]: GetRenderList::ordr_username
78    pub fn replay_username(&mut self, replay_username: &'a str) -> &mut Self {
79        self.fields.replay_username = Some(replay_username);
80
81        self
82    }
83
84    /// The render ID of a render.
85    pub fn render_id(&mut self, render_id: u32) -> &mut Self {
86        self.fields.render_id = Some(render_id);
87
88        self
89    }
90
91    /// Hide bots from the returned render query.
92    pub fn no_bots(&mut self, no_bots: bool) -> &mut Self {
93        self.fields.no_bots = Some(no_bots);
94
95        self
96    }
97
98    /// The path of a shortlink (for example `pov8n` for `https://link.issou.best/pov8n`)
99    pub fn link(&mut self, link: &'a str) -> &mut Self {
100        self.fields.link = Some(link);
101
102        self
103    }
104
105    /// Get renders with this specific beatmapset ID
106    pub fn mapset_id(&mut self, mapset_id: u32) -> &mut Self {
107        self.fields.mapset_id = Some(mapset_id);
108
109        self
110    }
111
112    fn request(&self) -> Result<Request, ClientError> {
113        Request::builder(Route::RenderList)
114            .query(&self.fields)
115            .map(RequestBuilder::build)
116    }
117}
118
119impl IntoFuture for &mut GetRenderList<'_> {
120    type Output = Result<RenderList, ClientError>;
121    type IntoFuture = OrdrFuture<RenderList>;
122
123    fn into_future(self) -> Self::IntoFuture {
124        match self.request() {
125            Ok(request) => self.ordr.request(request),
126            Err(err) => OrdrFuture::error(err),
127        }
128    }
129}
130
131impl IntoFuture for GetRenderList<'_> {
132    type Output = Result<RenderList, ClientError>;
133    type IntoFuture = OrdrFuture<RenderList>;
134
135    fn into_future(mut self) -> Self::IntoFuture {
136        (&mut self).into_future()
137    }
138}
139
140#[cfg(test)]
141mod tests {
142    use hyper::Method;
143
144    use crate::OrdrClient;
145
146    use super::GetRenderList;
147
148    fn path(list: &GetRenderList<'_>) -> String {
149        let request = list
150            .request()
151            .unwrap_or_else(|err| panic!("query serialization failed: {err}"));
152
153        assert_eq!(request.method, Method::GET);
154
155        request.path
156    }
157
158    #[test]
159    fn paging_and_render_id() {
160        let client = OrdrClient::builder().build();
161
162        let mut list = client.render_list();
163        list.page_size(25).page(2).render_id(42);
164
165        assert_eq!(path(&list), "renders?pageSize=25&page=2&renderID=42");
166    }
167
168    #[test]
169    fn filters() {
170        let client = OrdrClient::builder().build();
171
172        let mut list = client.render_list();
173        list.no_bots(true).link("pov8n").mapset_id(7);
174
175        assert_eq!(path(&list), "renders?nobots=true&link=pov8n&beatmapsetid=7");
176    }
177}