use std::{borrow::Cow, collections::BTreeSet, fmt::Display};
use serde::{Deserialize, Serialize};
use super::{
endpoint::Endpoint, error::BodyError, leaderboards::LeaderboardEmbeds,
query_params::QueryParams, CategoriesSorting, Direction, Pageable, VariablesSorting,
};
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum LevelEmbeds {
Categories,
Variables,
}
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
pub struct LevelId<'a>(Cow<'a, str>);
impl<'a> LevelId<'a> {
pub fn new<T>(id: T) -> Self
where
T: Into<Cow<'a, str>>,
{
Self(id.into())
}
}
impl<'a, T> From<T> for LevelId<'a>
where
T: Into<Cow<'a, str>>,
{
fn from(value: T) -> Self {
LevelId::new(value)
}
}
impl Display for LevelId<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", &self.0)
}
}
#[derive(Debug, Builder, Serialize, Clone)]
#[builder(setter(into, strip_option))]
pub struct Level<'a> {
#[doc = r"`ID` of the level."]
#[serde(skip)]
id: LevelId<'a>,
#[builder(setter(name = "_embed"), private, default)]
#[serde(serialize_with = "super::utils::serialize_as_csv")]
#[serde(skip_serializing_if = "BTreeSet::is_empty")]
embed: BTreeSet<LevelEmbeds>,
}
#[derive(Debug, Builder, Serialize, Clone)]
#[builder(setter(into, strip_option))]
#[serde(rename_all = "kebab-case")]
pub struct LevelCategories<'a> {
#[doc = r"`ID` of the level."]
#[serde(skip)]
id: LevelId<'a>,
#[doc = r"When give, filters miscellaneous categories."]
#[builder(default)]
miscellaneous: Option<bool>,
#[doc = r"Sorting options for results."]
#[builder(default)]
orderby: Option<CategoriesSorting>,
#[doc = r"Sort direction"]
#[builder(default)]
direction: Option<Direction>,
}
#[derive(Debug, Builder, Serialize, Clone)]
#[builder(setter(into, strip_option))]
#[serde(rename_all = "kebab-case")]
pub struct LevelVariables<'a> {
#[doc = r"`ID` of the level."]
#[serde(skip)]
id: LevelId<'a>,
#[doc = r"Sorting options for results."]
#[builder(default)]
orderby: Option<VariablesSorting>,
#[doc = r"Sort direction"]
#[builder(default)]
direction: Option<Direction>,
}
#[derive(Debug, Builder, Serialize, Clone)]
#[builder(setter(into, strip_option))]
#[serde(rename_all = "kebab-case")]
pub struct LevelRecords<'a> {
#[doc = r"`ID` of the level."]
#[serde(skip)]
id: LevelId<'a>,
#[doc = r"Return `top` number of places (default: 3)."]
#[builder(default)]
top: Option<i64>,
#[doc = r"Do not return empty leaderboards when `true`."]
#[builder(default)]
skip_empty: Option<bool>,
#[builder(setter(name = "_embed"), private, default)]
#[serde(serialize_with = "super::utils::serialize_as_csv")]
#[serde(skip_serializing_if = "BTreeSet::is_empty")]
embed: BTreeSet<LeaderboardEmbeds>,
}
impl Level<'_> {
pub fn builder<'a>() -> LevelBuilder<'a> {
LevelBuilder::default()
}
}
impl LevelBuilder<'_> {
pub fn embed(&mut self, embed: LevelEmbeds) -> &mut Self {
self.embed.get_or_insert_with(BTreeSet::new).insert(embed);
self
}
pub fn embeds<I>(&mut self, iter: I) -> &mut Self
where
I: Iterator<Item = LevelEmbeds>,
{
self.embed.get_or_insert_with(BTreeSet::new).extend(iter);
self
}
}
impl LevelCategories<'_> {
pub fn builder<'a>() -> LevelCategoriesBuilder<'a> {
LevelCategoriesBuilder::default()
}
}
impl LevelVariables<'_> {
pub fn builder<'a>() -> LevelVariablesBuilder<'a> {
LevelVariablesBuilder::default()
}
}
impl LevelRecords<'_> {
pub fn builder<'a>() -> LevelRecordsBuilder<'a> {
LevelRecordsBuilder::default()
}
}
impl LevelRecordsBuilder<'_> {
pub fn embed(&mut self, embed: LeaderboardEmbeds) -> &mut Self {
self.embed.get_or_insert_with(BTreeSet::new).insert(embed);
self
}
pub fn embeds<I>(&mut self, iter: I) -> &mut Self
where
I: Iterator<Item = LeaderboardEmbeds>,
{
self.embed.get_or_insert_with(BTreeSet::new).extend(iter);
self
}
}
impl LevelEmbeds {
fn as_str(&self) -> &'static str {
match self {
LevelEmbeds::Categories => "categories",
LevelEmbeds::Variables => "variables",
}
}
}
impl Endpoint for Level<'_> {
fn endpoint(&self) -> Cow<'static, str> {
format!("/levels/{}", self.id).into()
}
fn query_parameters(&self) -> Result<QueryParams<'_>, BodyError> {
QueryParams::with(self)
}
}
impl Endpoint for LevelCategories<'_> {
fn endpoint(&self) -> Cow<'static, str> {
format!("/levels/{}/categories", self.id).into()
}
fn query_parameters(&self) -> Result<QueryParams<'_>, BodyError> {
QueryParams::with(self)
}
}
impl Endpoint for LevelVariables<'_> {
fn endpoint(&self) -> Cow<'static, str> {
format!("/levels/{}/variables", self.id).into()
}
fn query_parameters(&self) -> Result<QueryParams<'_>, BodyError> {
QueryParams::with(self)
}
}
impl Endpoint for LevelRecords<'_> {
fn endpoint(&self) -> Cow<'static, str> {
format!("/levels/{}/records", self.id).into()
}
fn query_parameters(&self) -> Result<QueryParams<'_>, BodyError> {
QueryParams::with(self)
}
}
impl From<&LevelEmbeds> for &'static str {
fn from(value: &LevelEmbeds) -> Self {
value.as_str()
}
}
impl Pageable for LevelRecords<'_> {}