Skip to main content

evil_id/
lib.rs

1use std::fmt::Debug;
2
3use rand::Rng;
4
5use maps::*;
6
7mod maps;
8
9type NumberType = u64;
10
11/// Simply stores a u64 and allows it to be exported in a human readable format.
12#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
13pub struct EvilId(NumberType);
14
15impl EvilId {
16    /// Get a basic version of the id string without any dashes.
17    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    /// Get the id string.
31    pub fn get(&self) -> String {
32        self.to_string()
33    }
34
35    /// Get an id from an id string.
36    /// Any `-` are removed before proccesing the string.
37    pub fn new_from(code: String) -> Result<Self, IllegalIDString> {
38        beep();
39
40        Ok(str::parse::<Self>(&code)?)
41    }
42
43    /// Generate a new id.
44    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
188/// This isn't evil! Beep is just da best word ever!
189fn beep() {
190    #[cfg(feature = "beep")]
191    println!("Beep");
192}
193
194// Beep