acick_util/model/
contest.rs

1use std::cmp::Ordering;
2use std::convert::Infallible;
3use std::fmt;
4use std::hash::{Hash, Hasher};
5use std::str::FromStr;
6
7use getset::Getters;
8use serde::{Deserialize, Serialize};
9
10use crate::regex;
11
12pub static DEFAULT_CONTEST_ID_STR: &str = "arc100";
13static DEFAULT_CONTEST_NAME_STR: &str = "AtCoder Regular Contest 100";
14
15#[derive(Serialize, Deserialize, Getters, Debug, Clone, PartialEq, Eq, Hash)]
16#[get = "pub"]
17pub struct Contest {
18    id: ContestId,
19    name: String,
20}
21
22impl Contest {
23    pub fn new(id: impl Into<ContestId>, name: impl Into<String>) -> Self {
24        Self {
25            id: id.into(),
26            name: name.into(),
27        }
28    }
29}
30
31impl Default for Contest {
32    fn default() -> Self {
33        Self::new(DEFAULT_CONTEST_ID_STR, DEFAULT_CONTEST_NAME_STR)
34    }
35}
36
37#[derive(Serialize, Deserialize, Debug, Clone, Eq)]
38pub struct ContestId(String);
39
40impl ContestId {
41    pub fn normalize(&self) -> String {
42        regex!(r"[-_]").replace_all(&self.0, "").to_lowercase()
43    }
44}
45
46impl Default for ContestId {
47    fn default() -> Self {
48        Self::from(DEFAULT_CONTEST_ID_STR)
49    }
50}
51
52impl PartialEq<ContestId> for ContestId {
53    fn eq(&self, other: &ContestId) -> bool {
54        self.normalize() == other.normalize()
55    }
56}
57
58impl PartialOrd for ContestId {
59    fn partial_cmp(&self, other: &ContestId) -> Option<Ordering> {
60        Some(self.normalize().cmp(&other.normalize()))
61    }
62}
63
64impl Ord for ContestId {
65    fn cmp(&self, other: &Self) -> Ordering {
66        self.normalize().cmp(&other.normalize())
67    }
68}
69
70impl Hash for ContestId {
71    fn hash<H: Hasher>(&self, state: &mut H) {
72        self.normalize().hash(state);
73    }
74}
75
76impl<T: Into<String>> From<T> for ContestId {
77    fn from(id: T) -> Self {
78        Self(id.into())
79    }
80}
81
82impl FromStr for ContestId {
83    type Err = Infallible;
84
85    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
86        Ok(Self::from(s))
87    }
88}
89
90impl AsRef<str> for ContestId {
91    fn as_ref(&self) -> &str {
92        &self.0
93    }
94}
95
96impl fmt::Display for ContestId {
97    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
98        f.write_str(&self.0)
99    }
100}
101
102#[cfg(test)]
103mod tests {
104    use super::*;
105
106    #[test]
107    fn contest_id_eq() {
108        assert_eq!(ContestId::from("arc100"), ContestId::from("arc100"));
109        assert_eq!(ContestId::from("ARC100"), ContestId::from("arc100"));
110        assert_eq!(
111            ContestId::from("CodeFestival2017QualA"),
112            ContestId::from("code-festival-2017-quala"),
113        );
114    }
115
116    #[test]
117    fn test_contest_id_display() {
118        assert_eq!(&ContestId::from("arc100").to_string(), "arc100");
119        assert_eq!(&ContestId::from("ARC100").to_string(), "ARC100");
120        assert_eq!(
121            &ContestId::from("code-festival-2017-quala").to_string(),
122            "code-festival-2017-quala"
123        );
124    }
125}