meme_id/schemes/
punk.rs

1use core::fmt;
2
3use crate::{
4    dict::{Adjective, Mapper, ObjectPronoun, Singular, Verb},
5    Hyphenated,
6};
7
8use super::{string_to_words, Error};
9
10#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
11pub struct Punk {
12    pub verbs: [&'static str; 4],
13    pub pronouns: [&'static str; 4],
14    pub adjectives: [&'static str; 4],
15}
16
17impl Punk {
18    /// Encodes bits into `adjective noun verb adverb` scheme
19    #[inline]
20    pub fn encode(bits: u64) -> Self {
21        encode(bits)
22    }
23
24    /// Transform to hyphenated.
25    #[inline]
26    pub fn hyphenated(self) -> Hyphenated<Self> {
27        Hyphenated(self)
28    }
29}
30
31impl fmt::Display for Punk {
32    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33        write!(
34            f,
35            "{}{} {}{}, {}{} {}{}\n{}{} {}{}, {}{} {}{}\n{}{}, {}{}\n{}{}, {}{}",
36            &self.verbs[0].chars().next().unwrap().to_uppercase(),
37            &self.verbs[0][1..],
38            &self.pronouns[0].chars().next().unwrap().to_uppercase(),
39            &self.pronouns[0][1..],
40            &self.verbs[1].chars().next().unwrap().to_uppercase(),
41            &self.verbs[1][1..],
42            &self.pronouns[1].chars().next().unwrap().to_uppercase(),
43            &self.pronouns[1][1..],
44            &self.verbs[2].chars().next().unwrap().to_uppercase(),
45            &self.verbs[2][1..],
46            &self.pronouns[2].chars().next().unwrap().to_uppercase(),
47            &self.pronouns[2][1..],
48            &self.verbs[3].chars().next().unwrap().to_uppercase(),
49            &self.verbs[3][1..],
50            &self.pronouns[3].chars().next().unwrap().to_uppercase(),
51            &self.pronouns[3][1..],
52            &self.adjectives[0].chars().next().unwrap().to_uppercase(),
53            &self.adjectives[0][1..],
54            &self.adjectives[1].chars().next().unwrap().to_uppercase(),
55            &self.adjectives[1][1..],
56            &self.adjectives[2].chars().next().unwrap().to_uppercase(),
57            &self.adjectives[2][1..],
58            &self.adjectives[3].chars().next().unwrap().to_uppercase(),
59            &self.adjectives[3][1..],
60        )
61    }
62}
63
64impl fmt::Display for Hyphenated<Punk> {
65    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
66        write!(
67            f,
68            "{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}",
69            &self.0.verbs[0],
70            &self.0.pronouns[0],
71            &self.0.verbs[1],
72            &self.0.pronouns[1],
73            &self.0.verbs[2],
74            &self.0.pronouns[2],
75            &self.0.verbs[3],
76            &self.0.pronouns[3],
77            &self.0.adjectives[0],
78            &self.0.adjectives[1],
79            &self.0.adjectives[2],
80            &self.0.adjectives[3],
81        )
82    }
83}
84
85/// Encodes bits into a punky phrase.
86/// For 64-bit ids.
87pub fn encode(bits: u64) -> Punk {
88    let (verbs, bits) = Verb::<Singular>::encode_words(bits.into());
89    let (pronouns, bits) = ObjectPronoun::encode_words(bits.into());
90    let (adjectives, bits) = Adjective::encode_words(bits.into());
91
92    debug_assert_eq!(bits, 0);
93
94    Punk {
95        verbs,
96        pronouns,
97        adjectives,
98    }
99}
100
101/// Decodes a punky phrase.
102/// For 64-bit ids.
103pub fn decode(s: &str) -> Result<u64, Error> {
104    let mut split = string_to_words(s);
105
106    let verb1 = split.next().ok_or(Error::NotEnoughWords {
107        expected: 12,
108        actual: 0,
109    })?;
110    let pronoun1 = split.next().ok_or(Error::NotEnoughWords {
111        expected: 12,
112        actual: 1,
113    })?;
114    let verb2 = split.next().ok_or(Error::NotEnoughWords {
115        expected: 12,
116        actual: 2,
117    })?;
118    let pronoun2 = split.next().ok_or(Error::NotEnoughWords {
119        expected: 12,
120        actual: 3,
121    })?;
122    let verb3 = split.next().ok_or(Error::NotEnoughWords {
123        expected: 12,
124        actual: 4,
125    })?;
126    let pronoun3 = split.next().ok_or(Error::NotEnoughWords {
127        expected: 12,
128        actual: 5,
129    })?;
130    let verb4 = split.next().ok_or(Error::NotEnoughWords {
131        expected: 12,
132        actual: 6,
133    })?;
134    let pronoun4 = split.next().ok_or(Error::NotEnoughWords {
135        expected: 12,
136        actual: 7,
137    })?;
138    let adjective1 = split.next().ok_or(Error::NotEnoughWords {
139        expected: 12,
140        actual: 8,
141    })?;
142    let adjective2 = split.next().ok_or(Error::NotEnoughWords {
143        expected: 12,
144        actual: 9,
145    })?;
146    let adjective3 = split.next().ok_or(Error::NotEnoughWords {
147        expected: 12,
148        actual: 10,
149    })?;
150    let adjective4 = split.next().ok_or(Error::NotEnoughWords {
151        expected: 12,
152        actual: 11,
153    })?;
154
155    if split.next().is_some() {
156        return Err(Error::TrailingWords);
157    }
158
159    let adjectives = [adjective4, adjective3, adjective2, adjective1];
160    let pronouns = [pronoun4, pronoun3, pronoun2, pronoun1];
161    let verbs = [verb4, verb3, verb2, verb1];
162
163    let mut bits = 0;
164    bits = Adjective::decode_words(adjectives, bits).map_err(|i| Error::Unrecognized {
165        word: adjectives[i],
166    })?;
167    bits = ObjectPronoun::decode_words(pronouns, bits)
168        .map_err(|i| Error::Unrecognized { word: pronouns[i] })?;
169    bits = Verb::<Singular>::decode_words(verbs, bits)
170        .map_err(|i| Error::Unrecognized { word: verbs[i] })?;
171
172    Ok(bits as u64)
173}
174
175#[cfg(feature = "serde")]
176pub fn serialize<T, S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
177where
178    T: Copy + Into<u64>,
179    S: serde::ser::Serializer,
180{
181    use alloc::string::ToString;
182    use serde::Serialize;
183
184    let an = encode((*value).into());
185    an.to_string().serialize(serializer)
186}
187
188#[cfg(feature = "serde")]
189pub fn deserialize<'de, T, D>(deserializer: D) -> Result<T, D::Error>
190where
191    u64: Into<T>,
192    D: serde::de::Deserializer<'de>,
193{
194    use alloc::borrow::Cow;
195
196    let s = <Cow<str> as serde::de::Deserialize>::deserialize(deserializer)?;
197    match decode(&*s) {
198        Err(err) => Err(serde::de::Error::custom(err)),
199        Ok(id) => Ok(id.into()),
200    }
201}