From ae6056569e33c76c70ce77c27d865332839dd8ab Mon Sep 17 00:00:00 2001 From: Mingwei Samuel Date: Tue, 2 Jun 2020 12:45:40 -0700 Subject: [PATCH] Add UNRANKED to tier enum, fix #11 --- src/consts/division.rs | 6 +-- src/consts/ranks.rs | 21 ++++---- src/consts/tier.rs | 114 ++++++++++++++++++++++++++++++++++++++--- 3 files changed, 121 insertions(+), 20 deletions(-) diff --git a/src/consts/division.rs b/src/consts/division.rs index c9f1bf6..e51b28c 100644 --- a/src/consts/division.rs +++ b/src/consts/division.rs @@ -1,8 +1,8 @@ use std::cmp::Ordering; +use num_enum::{ IntoPrimitive, TryFromPrimitive }; use strum::IntoEnumIterator; use strum_macros::{ EnumString, Display, AsRefStr, IntoStaticStr }; -use num_enum::{ IntoPrimitive, TryFromPrimitive }; /// LoL and TFT rank divisions, I, II, III, IV, and (deprecated) V. /// @@ -31,9 +31,9 @@ serde_string!(Division); /// Ordered from high rank (I) to low (IV). /// Excludes V, which is deprecated. impl IntoEnumIterator for Division { - type Iterator = std::slice::Iter<'static, Self>; + type Iterator = std::iter::Copied>; fn iter() -> Self::Iterator { - [ Self::I, Self::II, Self::III, Self::IV ].iter() + [ Self::I, Self::II, Self::III, Self::IV ].iter().copied() } } diff --git a/src/consts/ranks.rs b/src/consts/ranks.rs index bd64b34..8def52b 100644 --- a/src/consts/ranks.rs +++ b/src/consts/ranks.rs @@ -6,6 +6,9 @@ use strum::IntoEnumIterator; use super::{ Tier, Division }; +/// (Tier, Division) tuple representing a rank. +pub type Rank = ( Tier, Division ); + /// Iterator for iterating `(Tier, Division)` rank tuples. pub struct Iter { tier_iter: Peekable<::Iterator>, @@ -13,11 +16,11 @@ pub struct Iter { } impl Iterator for Iter { - type Item = (Tier, Division); + type Item = Rank; fn next(&mut self) -> Option { // First find the tier (innermost loop). // If none found, we go to next tier (in unwrap_or_else case). - let div = *self.div_iter.next() + let div = self.div_iter.next() .unwrap_or_else(|| { // If no divisions available, go to next tier, reset the divisions, and return I. self.tier_iter.next(); @@ -33,7 +36,7 @@ impl Iterator for Iter { self.div_iter = Division::iter(); } - Some((tier, div)) + Some(( tier, div )) } } @@ -68,16 +71,16 @@ mod tests { #[test] fn iter() { let mut it = super::iter(); - assert_eq!(Some((Tier::CHALLENGER, Division::I)), it.next()); - assert_eq!(Some((Tier::GRANDMASTER, Division::I)), it.next()); - assert_eq!(Some((Tier::MASTER, Division::I)), it.next()); - assert_eq!(Some((Tier::DIAMOND, Division::I)), it.next()); - assert_eq!(Some((Tier::DIAMOND, Division::II)), it.next()); + assert_eq!(Some(( Tier::CHALLENGER, Division::I )), it.next()); + assert_eq!(Some(( Tier::GRANDMASTER, Division::I )), it.next()); + assert_eq!(Some(( Tier::MASTER, Division::I )), it.next()); + assert_eq!(Some(( Tier::DIAMOND, Division::I )), it.next()); + assert_eq!(Some(( Tier::DIAMOND, Division::II )), it.next()); let mut last = None; for next in &mut it { last = Some(next); } - assert_eq!(Some((Tier::IRON, Division::IV)), last); + assert_eq!(Some(( Tier::IRON, Division::IV )), last); assert_eq!(None, it.next()); } diff --git a/src/consts/tier.rs b/src/consts/tier.rs index 8e3446c..6f471e0 100644 --- a/src/consts/tier.rs +++ b/src/consts/tier.rs @@ -1,5 +1,6 @@ +use strum::IntoEnumIterator; use num_enum::{ IntoPrimitive, TryFromPrimitive }; -use strum_macros::{ EnumString, EnumIter, Display, AsRefStr, IntoStaticStr }; +use strum_macros::{ EnumString, Display, AsRefStr, IntoStaticStr }; /// LoL and TFT ranked tiers, such as gold, diamond, challenger, etc. /// @@ -11,7 +12,7 @@ use strum_macros::{ EnumString, EnumIter, Display, AsRefStr, IntoStaticStr }; #[derive(Debug, Copy, Clone)] #[derive(Eq, PartialEq, Hash, PartialOrd, Ord)] #[derive(IntoPrimitive, TryFromPrimitive)] -#[derive(EnumString, EnumIter, Display, AsRefStr, IntoStaticStr)] +#[derive(EnumString, Display, AsRefStr, IntoStaticStr)] #[repr(u8)] pub enum Tier { /// Challenger, the highest tier, an apex tier. Repr: `220_u8`. @@ -32,19 +33,64 @@ pub enum Tier { BRONZE = 60, /// Iron, the lowest tier. Repr: `40_u8`. IRON = 40, + + /// Unranked, no tier. Repr: `0_u8`. + UNRANKED = 0, } serde_string!(Tier); impl Tier { - /// If this tier is an apex tier: master and above. - /// - /// Inverse of is_standard(). + /// If this tier is an apex tier: master, grandmaster, or challenger. + /// Returns false for unranked. /// /// These tiers are NOT queryable by LeagueV4Endpoints::get_league_entries(...). pub const fn is_apex(self) -> bool { + // Casts needed for const. (Self::MASTER as u8) <= (self as u8) } + + /// If this tier is a "standard" tier: iron through diamond. + /// Returns false for unranked. + /// + /// ONLY these tiers are queryable by LeagueV4Endpoints::get_league_entries(...). + pub fn is_standard(self) -> bool { + // Casts needed for const. + ((Self::UNRANKED as u8) < (self as u8)) && ((self as u8) < (Self::MASTER as u8)) + } + + /// If this tier is ranked. Returns true for iron through challenger, false for unranked. + pub const fn is_ranked(self) -> bool { + // Casts needed for const. + (Self::UNRANKED as u8) < (self as u8) + } + + /// If this tier is unranked (`Tier::UNRANKED`). + /// + /// UNRANKED is returned by `Participant.highest_achieved_season_tier`. + pub const fn is_unranked(self) -> bool { + // Casts needed for const. + (self as u8) <= (Self::UNRANKED as u8) + } + + /// Converts UNRANKED to None and all ranked tiers to Some(...). + pub fn to_ranked(self) -> Option { + if self.is_unranked() { None } else { Some(self) } + } +} + +/// Returns a DoubleEndedIterator of I, II, III, IV. +/// Ordered from high rank (I) to low (IV). +/// Excludes V, which is deprecated. +impl IntoEnumIterator for Tier { + type Iterator = std::iter::Copied>; + fn iter() -> Self::Iterator { + [ + Self::CHALLENGER, Self::GRANDMASTER, Self::MASTER, + Self::DIAMOND, Self::PLATINUM, Self::GOLD, + Self::SILVER, Self::BRONZE, Self::IRON + ].iter().copied() + } } #[cfg(test)] @@ -52,30 +98,64 @@ mod tests { use super::*; #[test] - fn sort() { + fn ord() { assert!(Tier::GOLD < Tier::DIAMOND); + assert!(Tier::UNRANKED < Tier::IRON); } #[test] - fn apex_check() { - assert!( Tier::GRANDMASTER.is_apex()); + fn is_apex() { + assert!(Tier::GRANDMASTER.is_apex()); assert!(!Tier::DIAMOND.is_apex()); + assert!(!Tier::UNRANKED.is_apex()); + } + + #[test] + fn is_ranked() { + assert!(Tier::GRANDMASTER.is_ranked()); + assert!(Tier::DIAMOND.is_ranked()); + assert!(!Tier::UNRANKED.is_ranked()); + } + + #[test] + fn is_unranked() { + assert!(!Tier::GRANDMASTER.is_unranked()); + assert!(!Tier::DIAMOND.is_unranked()); + assert!(Tier::UNRANKED.is_unranked()); + } + + #[test] + fn to_ranked() { + assert_eq!(Some(Tier::GRANDMASTER), Tier::GRANDMASTER.to_ranked()); + assert_eq!(Some(Tier::DIAMOND), Tier::DIAMOND.to_ranked()); + assert_eq!(None, Tier::UNRANKED.to_ranked()); + } + + #[test] + fn is_standard() { + assert!(!Tier::GRANDMASTER.is_standard()); + assert!(Tier::DIAMOND.is_standard()); + assert!(!Tier::UNRANKED.is_standard()); } #[test] fn to_string() { assert_eq!("GRANDMASTER", Tier::GRANDMASTER.as_ref()); assert_eq!("GRANDMASTER", Tier::GRANDMASTER.to_string()); + assert_eq!("UNRANKED", Tier::UNRANKED.as_ref()); + assert_eq!("UNRANKED", Tier::UNRANKED.to_string()); } #[test] fn from_string() { assert_eq!(Ok(Tier::GRANDMASTER), "GRANDMASTER".parse()); + assert_eq!(Ok(Tier::UNRANKED), "UNRANKED".parse()); } #[test] fn iter() { use strum::IntoEnumIterator; + let mut iter = Tier::iter(); assert_eq!(Some(Tier::CHALLENGER), iter.next()); iter.next(); @@ -87,5 +167,23 @@ mod tests { iter.next(); assert_eq!(Some(Tier::IRON), iter.next()); assert_eq!(None, iter.next()); + assert_eq!(None, iter.next_back()); + + let mut iter = Tier::iter().rev(); + assert_eq!(Some(Tier::IRON), iter.next()); + iter.next(); + iter.next(); + iter.next(); + iter.next(); + assert_eq!(Some(Tier::DIAMOND), iter.next()); + iter.next(); + iter.next(); + assert_eq!(Some(Tier::CHALLENGER), iter.next()); + assert_eq!(None, iter.next()); + assert_eq!(None, iter.next_back()); + + let mut iter = Tier::iter(); + assert_eq!(Some(Tier::CHALLENGER), iter.next()); + assert_eq!(Some(Tier::IRON), iter.next_back()); } }