1use std::{borrow::Cow, collections::BTreeSet, fmt::Display};
5
6use serde::{Deserialize, Serialize};
7
8use super::{
9 endpoint::Endpoint, error::BodyError, leaderboards::LeaderboardEmbeds,
10 query_params::QueryParams, CategoriesSorting, Direction, Pageable, VariablesSorting,
11};
12
13#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
15pub enum LevelEmbeds {
16 Categories,
18 Variables,
20}
21
22#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
24pub struct LevelId<'a>(Cow<'a, str>);
25
26impl<'a> LevelId<'a> {
27 pub fn new<T>(id: T) -> Self
29 where
30 T: Into<Cow<'a, str>>,
31 {
32 Self(id.into())
33 }
34}
35
36impl<'a, T> From<T> for LevelId<'a>
37where
38 T: Into<Cow<'a, str>>,
39{
40 fn from(value: T) -> Self {
41 LevelId::new(value)
42 }
43}
44
45impl Display for LevelId<'_> {
46 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
47 write!(f, "{}", &self.0)
48 }
49}
50
51#[derive(Debug, Builder, Serialize, Clone)]
53#[builder(setter(into, strip_option))]
54pub struct Level<'a> {
55 #[doc = r"`ID` of the level."]
56 #[serde(skip)]
57 id: LevelId<'a>,
58 #[builder(setter(name = "_embed"), private, default)]
59 #[serde(serialize_with = "super::utils::serialize_as_csv")]
60 #[serde(skip_serializing_if = "BTreeSet::is_empty")]
61 embed: BTreeSet<LevelEmbeds>,
62}
63
64#[derive(Debug, Builder, Serialize, Clone)]
66#[builder(setter(into, strip_option))]
67#[serde(rename_all = "kebab-case")]
68pub struct LevelCategories<'a> {
69 #[doc = r"`ID` of the level."]
70 #[serde(skip)]
71 id: LevelId<'a>,
72 #[doc = r"When give, filters miscellaneous categories."]
73 #[builder(default)]
74 miscellaneous: Option<bool>,
75 #[doc = r"Sorting options for results."]
76 #[builder(default)]
77 orderby: Option<CategoriesSorting>,
78 #[doc = r"Sort direction"]
79 #[builder(default)]
80 direction: Option<Direction>,
81}
82
83#[derive(Debug, Builder, Serialize, Clone)]
85#[builder(setter(into, strip_option))]
86#[serde(rename_all = "kebab-case")]
87pub struct LevelVariables<'a> {
88 #[doc = r"`ID` of the level."]
89 #[serde(skip)]
90 id: LevelId<'a>,
91 #[doc = r"Sorting options for results."]
92 #[builder(default)]
93 orderby: Option<VariablesSorting>,
94 #[doc = r"Sort direction"]
95 #[builder(default)]
96 direction: Option<Direction>,
97}
98
99#[derive(Debug, Builder, Serialize, Clone)]
101#[builder(setter(into, strip_option))]
102#[serde(rename_all = "kebab-case")]
103pub struct LevelRecords<'a> {
104 #[doc = r"`ID` of the level."]
105 #[serde(skip)]
106 id: LevelId<'a>,
107 #[doc = r"Return `top` number of places (default: 3)."]
108 #[builder(default)]
109 top: Option<i64>,
110 #[doc = r"Do not return empty leaderboards when `true`."]
111 #[builder(default)]
112 skip_empty: Option<bool>,
113 #[builder(setter(name = "_embed"), private, default)]
114 #[serde(serialize_with = "super::utils::serialize_as_csv")]
115 #[serde(skip_serializing_if = "BTreeSet::is_empty")]
116 embed: BTreeSet<LeaderboardEmbeds>,
117}
118
119impl Level<'_> {
120 pub fn builder<'a>() -> LevelBuilder<'a> {
122 LevelBuilder::default()
123 }
124}
125
126impl LevelBuilder<'_> {
127 pub fn embed(&mut self, embed: LevelEmbeds) -> &mut Self {
129 self.embed.get_or_insert_with(BTreeSet::new).insert(embed);
130 self
131 }
132
133 pub fn embeds<I>(&mut self, iter: I) -> &mut Self
135 where
136 I: Iterator<Item = LevelEmbeds>,
137 {
138 self.embed.get_or_insert_with(BTreeSet::new).extend(iter);
139 self
140 }
141}
142
143impl LevelCategories<'_> {
144 pub fn builder<'a>() -> LevelCategoriesBuilder<'a> {
146 LevelCategoriesBuilder::default()
147 }
148}
149
150impl LevelVariables<'_> {
151 pub fn builder<'a>() -> LevelVariablesBuilder<'a> {
153 LevelVariablesBuilder::default()
154 }
155}
156
157impl LevelRecords<'_> {
158 pub fn builder<'a>() -> LevelRecordsBuilder<'a> {
160 LevelRecordsBuilder::default()
161 }
162}
163
164impl LevelRecordsBuilder<'_> {
165 pub fn embed(&mut self, embed: LeaderboardEmbeds) -> &mut Self {
167 self.embed.get_or_insert_with(BTreeSet::new).insert(embed);
168 self
169 }
170
171 pub fn embeds<I>(&mut self, iter: I) -> &mut Self
173 where
174 I: Iterator<Item = LeaderboardEmbeds>,
175 {
176 self.embed.get_or_insert_with(BTreeSet::new).extend(iter);
177 self
178 }
179}
180
181impl LevelEmbeds {
182 fn as_str(&self) -> &'static str {
183 match self {
184 LevelEmbeds::Categories => "categories",
185 LevelEmbeds::Variables => "variables",
186 }
187 }
188}
189
190impl Endpoint for Level<'_> {
191 fn endpoint(&self) -> Cow<'static, str> {
192 format!("/levels/{}", self.id).into()
193 }
194
195 fn query_parameters(&self) -> Result<QueryParams<'_>, BodyError> {
196 QueryParams::with(self)
197 }
198}
199
200impl Endpoint for LevelCategories<'_> {
201 fn endpoint(&self) -> Cow<'static, str> {
202 format!("/levels/{}/categories", self.id).into()
203 }
204
205 fn query_parameters(&self) -> Result<QueryParams<'_>, BodyError> {
206 QueryParams::with(self)
207 }
208}
209
210impl Endpoint for LevelVariables<'_> {
211 fn endpoint(&self) -> Cow<'static, str> {
212 format!("/levels/{}/variables", self.id).into()
213 }
214
215 fn query_parameters(&self) -> Result<QueryParams<'_>, BodyError> {
216 QueryParams::with(self)
217 }
218}
219
220impl Endpoint for LevelRecords<'_> {
221 fn endpoint(&self) -> Cow<'static, str> {
222 format!("/levels/{}/records", self.id).into()
223 }
224
225 fn query_parameters(&self) -> Result<QueryParams<'_>, BodyError> {
226 QueryParams::with(self)
227 }
228}
229
230impl From<&LevelEmbeds> for &'static str {
231 fn from(value: &LevelEmbeds) -> Self {
232 value.as_str()
233 }
234}
235
236impl Pageable for LevelRecords<'_> {}