mcsr_ranked_api/pagination/
mod.rs

1use std::{error::Error, fmt::Display, num::NonZeroU8};
2
3use serde::Serialize;
4
5#[cfg(test)]
6mod tests;
7
8/// Pagination error type
9#[derive(Debug, Clone, PartialEq, Eq)]
10pub enum PaginationError {
11	/// Incorrect page count
12	Page(u8),
13	/// Incorrect entry count
14	Count(u8),
15}
16
17impl Display for PaginationError {
18	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
19		use PaginationError as Err;
20
21		match self {
22			Err::Page(p) => write!(f, "Page number {p} is not within bounds [0; 99]"),
23			Err::Count(c) => write!(f, "Item count {c} is not within bounds [1; 50]"),
24		}
25	}
26}
27impl Error for PaginationError {}
28
29/// Pagination struct for GET requests
30#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
31#[serde(rename_all = "camelCase")]
32pub struct Pagination {
33	/// Page number, 0-indexed
34	///
35	/// Default is 0
36	page: u8,
37	/// Item count
38	///
39	/// Default is 10
40	count: NonZeroU8,
41}
42
43impl Default for Pagination {
44	fn default() -> Self {
45		Self {
46			page: 0,
47			count: const { NonZeroU8::new(10).unwrap() },
48		}
49	}
50}
51
52impl Pagination {
53	/// Try to create a new pagination with `page` number and item `count`
54	///
55	/// # Limitations
56	/// The `page` must be within the range \[0; 99\] inclusive
57	///
58	/// The `count` must be within the range \[1; 50\] inclusive
59	pub fn new(page: u8, count: u8) -> Result<Self, PaginationError> {
60		let opt_count = NonZeroU8::new(count);
61		match (page, opt_count.map(|c| (c, c.get()))) {
62			(0..=99, Some((count, 1..=50))) => Ok(Self { page, count }),
63			(0..=99, _) => Err(PaginationError::Count(count)),
64			(_, _) => Err(PaginationError::Page(page)),
65		}
66	}
67
68	/// Try to crerate a new pagination with just the `page` number
69	pub fn page(page: u8) -> Result<Self, PaginationError> {
70		match page {
71			0..=99 => Ok(Self {
72				page,
73				..Default::default()
74			}),
75			_ => Err(PaginationError::Page(page)),
76		}
77	}
78
79	/// Try to crerate a new pagination with just the item `count`
80	pub fn count(count: u8) -> Result<Self, PaginationError> {
81		let opt_count = NonZeroU8::new(count);
82		match opt_count.map(|c| (c, c.get())) {
83			Some((count, 1..=50)) => Ok(Self {
84				count,
85				..Default::default()
86			}),
87			_ => Err(PaginationError::Count(count)),
88		}
89	}
90
91	/// Create a new pagination, not checking for bounds
92	///
93	/// # Safety
94	/// The `page` must be within the range \[0; 99\] inclusive
95	///
96	/// The `count` must be within the range \[1; 50\] inclusive
97	///
98	/// Breaking these bounds will result in a
99	pub unsafe fn new_unchecked(page: u8, count: u8) -> Self {
100		Self {
101			page,
102			count: unsafe { NonZeroU8::new_unchecked(count) },
103		}
104	}
105}