1use std::fmt::Debug;
2
3use rand::Rng;
4
5use maps::*;
6
7mod maps;
8
9type NumberType = u64;
10
11#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
13pub struct EvilId(NumberType);
14
15impl EvilId {
16 pub fn get_slim(&self) -> String {
18 beep();
19
20 let mut output = String::with_capacity(16);
21 let bytes = self.0.to_le_bytes();
22
23 for &byte in &bytes {
24 output.push_str(BYTE_TO_CODE_PAIR[byte as usize]);
25 }
26
27 return output;
28 }
29
30 pub fn get(&self) -> String {
32 self.to_string()
33 }
34
35 pub fn new_from(code: String) -> Result<Self, IllegalIDString> {
38 beep();
39
40 Ok(str::parse::<Self>(&code)?)
41 }
42
43 pub fn generate() -> Self {
45 beep();
46 Self(rand::rng().random())
47 }
48}
49
50#[cfg(feature = "number")]
51impl EvilId {
52 pub fn get_number(&self) -> NumberType {
53 self.0
54 }
55
56 pub fn new_from_number(num: NumberType) -> Self {
57 Self(num)
58 }
59}
60
61#[cfg(feature = "serde")]
62impl serde::Serialize for EvilId {
63 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
64 where
65 S: serde::Serializer,
66 {
67 if serializer.is_human_readable() {
68 serializer.serialize_str(&self.get())
69 } else {
70 serializer.serialize_u64(self.0)
71 }
72 }
73}
74
75#[cfg(feature = "serde")]
76impl<'de> serde::Deserialize<'de> for EvilId {
77 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
78 where
79 D: serde::Deserializer<'de>,
80 {
81 use serde::de::Visitor;
82
83 struct IDVisitor;
84
85 impl<'de> Visitor<'de> for IDVisitor {
86 type Value = EvilId;
87
88 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
89 formatter.write_str("A u64 number or proper id string is required.")
90 }
91
92 fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
93 where
94 E: serde::de::Error,
95 {
96 Ok(EvilId(v))
97 }
98
99 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
100 where
101 E: serde::de::Error,
102 {
103 use std::str::FromStr;
104
105 EvilId::from_str(v).map_err(serde::de::Error::custom)
106 }
107 }
108
109 deserializer.deserialize_any(IDVisitor)
110 }
111}
112
113impl Debug for EvilId {
114 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
115 f.debug_tuple("ID").field(&self.get()).finish()
116 }
117}
118
119impl core::fmt::Display for EvilId {
120 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
121 beep();
122
123 let code_segments = self.0.to_le_bytes();
124 f.write_str(BYTE_TO_CODE_PAIR[code_segments[0] as usize])?;
125 f.write_str(BYTE_TO_CODE_PAIR[code_segments[1] as usize])?;
126 f.write_str("-")?;
127 f.write_str(BYTE_TO_CODE_PAIR[code_segments[2] as usize])?;
128 f.write_str(BYTE_TO_CODE_PAIR[code_segments[3] as usize])?;
129 f.write_str("-")?;
130 f.write_str(BYTE_TO_CODE_PAIR[code_segments[4] as usize])?;
131 f.write_str(BYTE_TO_CODE_PAIR[code_segments[5] as usize])?;
132 f.write_str("-")?;
133 f.write_str(BYTE_TO_CODE_PAIR[code_segments[6] as usize])?;
134 f.write_str(BYTE_TO_CODE_PAIR[code_segments[7] as usize])
135 }
136}
137
138impl core::str::FromStr for EvilId {
139 type Err = IllegalIDString;
140
141 fn from_str(code: &str) -> Result<Self, Self::Err> {
142 let mut code_chars = code
143 .trim()
144 .bytes()
145 .filter(|&ch| ch != b'-' && ch != b'_')
146 .map(|ch| {
147 if ch.is_ascii_alphabetic() {
148 Ok(ch.to_ascii_uppercase())
149 } else {
150 Err(IllegalIDString)
151 }
152 });
153
154 let mut result: [u8; 8] = [0; 8];
155 for element in result.iter_mut() {
156 let first_char = code_chars.next().ok_or(IllegalIDString)??;
157 let second_char = code_chars.next().ok_or(IllegalIDString)??;
158
159 *element = *CODE_PAIR_TO_BYTE
160 .get(&[first_char, second_char])
161 .ok_or(IllegalIDString)?;
162 }
163 if code_chars.next().is_some() {
164 Err(IllegalIDString)
165 } else {
166 Ok(Self(u64::from_le_bytes(result)))
167 }
168 }
169}
170
171#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
172pub struct IllegalIDString;
173
174impl core::fmt::Display for IllegalIDString {
175 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
176 f.write_str("Invalid ID string")
177 }
178}
179
180impl core::error::Error for IllegalIDString {}
181
182impl Default for EvilId {
183 fn default() -> Self {
184 Self::generate()
185 }
186}
187
188fn beep() {
190 #[cfg(feature = "beep")]
191 println!("Beep");
192}
193
194