acick_util/model/
contest.rs1use 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}