1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
use super::{Pending, UserIdentification};
use crate::{
    model::{GameMode, GameMods, Score},
    routing::Route,
    Osu,
};

#[cfg(feature = "cache")]
use crate::client::cached::OsuCached;

/// Retrieve a [`Score`](crate::model::Score).
pub struct GetScore<'a> {
    fut: Option<Pending<'a>>,
    osu: Option<&'a Osu>,

    limit: Option<u32>,
    map_id: u32,
    mode: Option<GameMode>,
    mods: Option<GameMods>,
    user: Option<UserIdentification>,
}

/// Retrieve [`Score`](crate::model::Score)s
pub struct GetScores<'a> {
    fut: Option<Pending<'a>>,
    osu: Option<&'a Osu>,

    limit: Option<u32>,
    map_id: u32,
    mode: Option<GameMode>,
    mods: Option<GameMods>,
    user: Option<UserIdentification>,
}

macro_rules! impl_score {
    ($name: ident, $default_limit: expr) => {
        impl<'a> $name<'a> {
            pub(crate) fn new(osu: &'a Osu, map_id: u32) -> Self {
                Self {
                    osu: Some(osu),
                    map_id,
                    fut: None,
                    limit: $default_limit,
                    mode: None,
                    mods: None,
                    user: None,
                }
            }

            /// Optional, specify a user either by id (`u32`) or name (`String`/`&str`).
            pub fn user(mut self, user: impl Into<UserIdentification>) -> Self {
                self.user.replace(user.into());

                self
            }

            /// Optional, amount of results from the top.
            /// Range between 1 and 100, defaults to 50.
            pub fn limit(mut self, limit: u32) -> Self {
                self.limit.replace(limit.max(1).min(100));

                self
            }

            /// Optional, defaults to `GameMode::STD`.
            pub fn mode(mut self, mode: GameMode) -> Self {
                self.mode.replace(mode);

                self
            }

            /// Optional, specify a mod combination.
            pub fn mods(mut self, mods: GameMods) -> Self {
                self.mods.replace(mods);

                self
            }

            fn start(&mut self) {
                let route = Route::GetScore {
                    limit: self.limit.take(),
                    map_id: self.map_id,
                    mode: self.mode.take(),
                    mods: self.mods.take(),
                    user: self.user.take(),
                };

                #[cfg(feature = "metrics")]
                self.osu.unwrap().0.metrics.scores.inc();

                #[cfg(feature = "cache")]
                self.fut.replace(Box::pin(
                    self.osu.unwrap().request_bytes(route, OsuCached::Score),
                ));

                #[cfg(not(feature = "cache"))]
                self.fut
                    .replace(Box::pin(self.osu.unwrap().request_bytes(route)));
            }
        }
    };
}

impl_score!(GetScores, None);
poll_vec_req!(GetScores<'_>, Score);

impl_score!(GetScore, Some(1));
poll_req!(GetScore<'_>, Score);