emojic 0.5.1

Emoji constants
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
//!
//! Contains various emoji attributes.
//!

use core::fmt;

/// Unicode Emoji version.
///
/// This struct is used by [`Emoji`](super::Emoji) to denote when an emoji was introduced.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Version(pub u64, pub u64);
impl fmt::Display for Version {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{}.{}", self.0, self.1)
    }
}

/// Skin tone attribute πŸ–οΈπŸ–πŸ»πŸ–πŸΌπŸ–πŸ½πŸ–πŸΎπŸ–πŸΏ
///
/// Allows to specify the skin tone of supported emojis. Generally speaking, those involving people
/// or (some) body parts.
///
/// The default skin tone is πŸ–οΈ (typically some yellow-ish)
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(u8)]
pub enum Tone {
    /// Represents the least pigmented skin tone πŸ–πŸ»
    Light,
    /// Represents the second least pigmented skin tone πŸ–πŸΌ
    MediumLight,
    /// Represents intermediately pigmented skin tone πŸ–πŸ½
    Medium,
    /// Represents the second most pigmented skin tone πŸ–πŸΎ
    MediumDark,
    /// Represents the most pigmented skin tone πŸ–πŸΏ
    Dark,
}
impl Tone {
    /// Exhaustive list of all variants
    pub const ALL: [Tone; 5] = [
        Self::Light,
        Self::MediumLight,
        Self::Medium,
        Self::MediumDark,
        Self::Dark,
    ];

    /// Descriptive name of this attribute variant
    pub const fn name(self) -> &'static str {
        match self {
            Self::Light => "light skin tone",
            Self::MediumLight => "medium-light skin tone",
            Self::Medium => "medium skin tone",
            Self::MediumDark => "medium-dark skin tone",
            Self::Dark => "dark skin tone",
        }
    }
}

/// Represents a skin [`Tone`] pair.
///
/// Simply contains two independent skin tones. This allows emojis with two people to be
/// differently toned. E.g.: πŸ§‘πŸ»β€πŸ€β€πŸ§‘πŸΌπŸ§‘πŸΌβ€πŸ€β€πŸ§‘πŸΎπŸ§‘πŸΏβ€πŸ€β€πŸ§‘πŸ»
#[derive(Clone, Debug, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct TonePair {
    /// The left hand side person's skin tone
    pub left: Tone,
    /// The right hand side person's skin tone
    pub right: Tone,
}
impl TonePair {
    /// Returns the entry index for this pair
    pub(crate) const fn to_id(self) -> usize {
        self.left as usize * Tone::ALL.len() + self.right as usize
    }
}
impl From<Tone> for TonePair {
    fn from(both: Tone) -> Self {
        TonePair {
            left: both,
            right: both,
        }
    }
}
impl From<(Tone, Tone)> for TonePair {
    fn from((left, right): (Tone, Tone)) -> Self {
        TonePair { left, right }
    }
}

/* Actually this does not exist currently in Unicode 13.1, so it doesn't make a lot of sens to put
   it into the public API.

/// Represents a skin [`Tone`] pair with limited extend.
///
// This is only a reduced pair of tones, always ensure: left <= right
#[derive(Clone, Debug, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct TonePairReduced {
    pub left: Tone,
    pub right: Tone,
}
impl TonePairReduced {
    /// Returns the entry index for this pair
    pub(crate) to_id(self) -> usize {
        assert!(self.left <= self.right);
        const D: usize = Tone::ALL.len();

        let l = self.left as usize;
        let r = self.right as usize;

        D * l - l * (l + 1) / 2 + r
    }
}
impl From<Tone> for TonePairReduced {
    fn from(both: Tone) -> Self {
        TonePairReduced {
            left: both,
            right: both,
        }
    }
}
impl From<(Tone, Tone)> for TonePairReduced {
    fn from((mut left, mut right): (Tone, Tone)) -> Self {
        if left <= right {
            TonePairReduced { left, right }
        } else {
            // Ensure order
            std::mem::swap(&mut left, &mut right);
            TonePairReduced { left, right }
        }
    }
}

*/

/// Gender attribute πŸ§‘πŸ‘¨πŸ‘©
///
/// Allows to specify the gender of supported emojis. Generally speaking, those involving people.
///
/// The default gender is πŸ§‘ (a generic person somewhat genderless)
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(u8)]
pub enum Gender {
    /// Represents the male gender πŸ‘¨
    Male,
    /// Represents the female gender πŸ‘©
    Female,
}
impl Gender {
    /// Exhaustive list of all variants
    pub const ALL: [Gender; 2] = [Self::Male, Self::Female];

    /// [`Family`] composer using `self` as parent
    pub fn with_children(self, children: impl Into<OneOrTwo>) -> Family {
        (self, children).into()
    }

    /// Descriptive name of this attribute variant as adults
    pub const fn name_adults(self) -> &'static str {
        match self {
            Self::Male => "man",
            Self::Female => "woman",
        }
    }

    /// Descriptive name of this attribute variant as children
    pub const fn name_children(self) -> &'static str {
        match self {
            Self::Male => "boy",
            Self::Female => "girl",
        }
    }
}

/// Represents the gender of a pair of people πŸ§‘β€πŸ€β€πŸ§‘πŸ‘¬πŸ‘«πŸ‘­
///
/// This allows emojis with two people to specify their gender.
///
/// The default is πŸ§‘β€πŸ€β€πŸ§‘ (two genderless people)
#[derive(Clone, Debug, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(u8)]
pub enum Pair {
    /// Two males πŸ‘¬
    Males,
    /// A female and a male πŸ‘«
    Mixed,
    /// Two females πŸ‘­
    Females,
}
impl Pair {
    /// Exhaustive list of all variants
    pub const ALL: [Pair; 3] = [Self::Males, Self::Mixed, Self::Females];

    /// [`Family`] composer using `self` as parents
    pub fn with_children(self, children: impl Into<OneOrTwo>) -> Family {
        (self, children).into()
    }

    /// Descriptive name of this attribute variant as adults
    pub const fn name_adults(self) -> &'static str {
        match self {
            Self::Males => "men",
            Self::Mixed => "man & woman",
            Self::Females => "women",
        }
    }
    /// Descriptive name of this attribute variant as children
    pub const fn name_children(self) -> &'static str {
        match self {
            Self::Males => "boys",
            Self::Mixed => "boy & girl",
            Self::Females => "girls",
        }
    }
}
impl From<(Gender, Gender)> for Pair {
    fn from(pair: (Gender, Gender)) -> Self {
        match pair {
            (Gender::Male, Gender::Male) => Pair::Males,
            (Gender::Male, Gender::Female) => Pair::Mixed,
            (Gender::Female, Gender::Male) => Pair::Mixed,
            (Gender::Female, Gender::Female) => Pair::Females,
        }
    }
}

/// Represents one's or two person's gender while defining whether it's one or two.
///
/// Actually, this attribute is not used as such by any emoji, instead, it is used to compose
/// a [`Family`], which consists of two `OneOrTwo` structs.
///
/// E.g. one: πŸ‘¨β€πŸ‘¦ (parent), two: πŸ‘¨β€πŸ‘¨β€πŸ‘¦ (parents)
///
/// To get a `OneOrTwo` value, it is recommended to use any of the `From` impls e.g.:
///
/// ```rust
/// # use emojic::emojis::{OneOrTwo,Pair,Gender};
/// // From<Gender>
/// assert_eq!(OneOrTwo::One(Gender::Male), Gender::Male.into());
/// // From<Pair>
/// assert_eq!(OneOrTwo::Two(Pair::Males), Pair::Males.into());
/// ```
///
#[derive(Clone, Debug, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum OneOrTwo {
    /// Only one person
    One(Gender),
    /// Two people
    Two(Pair),
}
impl OneOrTwo {
    /// Exhaustive list of all variants
    pub const ALL: [OneOrTwo; 5] = [
        Self::One(Gender::Male),
        Self::One(Gender::Female),
        Self::Two(Pair::Males),
        Self::Two(Pair::Mixed),
        Self::Two(Pair::Females),
    ];

    /// Returns the entry index for this pair
    pub(crate) const fn to_id(self) -> usize {
        match self {
            Self::One(Gender::Male) => 0,
            Self::One(Gender::Female) => 1,
            Self::Two(Pair::Males) => 2,
            Self::Two(Pair::Mixed) => 3,
            Self::Two(Pair::Females) => 4,
        }
    }

    /// [`Family`] composer using `self` as parents
    pub fn with_children(self, children: impl Into<OneOrTwo>) -> Family {
        (self, children).into()
    }

    /// Descriptive name of this attribute variant
    pub const fn name_adults(self) -> &'static str {
        match self {
            Self::One(one) => one.name_adults(),
            Self::Two(two) => two.name_adults(),
        }
    }
    /// Descriptive name of this attribute variant
    pub const fn name_children(self) -> &'static str {
        match self {
            Self::One(one) => one.name_children(),
            Self::Two(two) => two.name_children(),
        }
    }
}
impl From<Gender> for OneOrTwo {
    fn from(g: Gender) -> Self {
        Self::One(g)
    }
}
impl From<Pair> for OneOrTwo {
    fn from(couple: Pair) -> Self {
        Self::Two(couple)
    }
}
impl From<(Gender, Gender)> for OneOrTwo {
    fn from(pair: (Gender, Gender)) -> Self {
        Self::Two(Pair::from(pair))
    }
}
impl From<(Gender, Option<Gender>)> for OneOrTwo {
    fn from(pair: (Gender, Option<Gender>)) -> Self {
        if let Some(g2) = pair.1 {
            Self::from((pair.0, g2))
        } else {
            Self::from(pair.0)
        }
    }
}

/// Represents the genders of an entire family with parents and children.
///
/// A Family consists of parents and children, each either a single or two persons as
/// expressed by the [`OneOrTwo`] struct.
///
/// E.g.:
///  - one parent & one child: πŸ‘¨β€πŸ‘¦
///  - two parents & one child: πŸ‘¨β€πŸ‘¨β€πŸ‘¦
///  - one parent & two children: πŸ‘©β€πŸ‘§β€πŸ‘¦
///  - and so on...
///
/// To get a `Family` value, it is recommended to use any of the `From` impls e.g.:
///
/// ```rust
/// # use emojic::emojis::{Family,OneOrTwo,Pair,Gender};
/// // From<(Gender,Gender)>
/// assert_eq!(
///     Family {
///         parents: OneOrTwo::One(Gender::Male),
///         children: OneOrTwo::One(Gender::Male),
///     },
///     (Gender::Male,Gender::Male).into()
/// );
/// // From<(Pair,Pair)>
/// assert_eq!(
///     Family {
///         parents: OneOrTwo::Two(Pair::Males),
///         children: OneOrTwo::Two(Pair::Males),
///     },
///     (Pair::Males,Pair::Males).into()
/// );
/// ```
///
/// Or use the `with_children` composer of [`Gender`] and [`Pair`]:
///
/// ```rust
/// # use emojic::emojis::{Family,OneOrTwo,Pair,Gender};
/// // Gender::with_children
/// assert_eq!(
///     Family {
///         parents: OneOrTwo::One(Gender::Male),
///         children: OneOrTwo::One(Gender::Male),
///     },
///     Gender::Male.with_children(Gender::Male)
/// );
/// // Pair::with_children
/// assert_eq!(
///     Family {
///         parents: OneOrTwo::Two(Pair::Males),
///         children: OneOrTwo::Two(Pair::Males),
///     },
///     Pair::Males.with_children(Pair::Males)
/// );
/// ```
#[derive(Clone, Debug, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Family {
    pub parents: OneOrTwo,
    pub children: OneOrTwo,
}
impl Family {
    /// Returns the entry index for this constellation
    pub(crate) const fn to_id(self) -> usize {
        self.parents.to_id() * OneOrTwo::ALL.len() + self.children.to_id()
    }
}
impl<A: Into<OneOrTwo>, B: Into<OneOrTwo>> From<(A, B)> for Family {
    fn from((parents, children): (A, B)) -> Self {
        Family {
            parents: parents.into(),
            children: children.into(),
        }
    }
}

/// Hair style attribute πŸ§‘πŸ§”πŸ‘±πŸ‘¨β€πŸ¦°πŸ‘¨β€πŸ¦±πŸ‘¨β€πŸ¦³πŸ‘¨β€πŸ¦²
///
/// Allows to specify the hair style of supported emojis. Generally speaking, those involving
/// people (well currently only of a single person).
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(u8)]
pub enum Hair {
    /// Represents a bearded person πŸ§”
    Beard,
    /// Represents a person with blond hair πŸ‘±
    Blond,
    /// Represents a person with red hair πŸ‘¨β€πŸ¦°
    Red,
    /// Represents a person with curly hair πŸ‘¨β€πŸ¦±
    Curly,
    /// Represents a person with white hair πŸ‘¨β€πŸ¦³
    ///
    /// Not to be confused with an older person πŸ§“
    White,
    /// Represents a person without hair πŸ‘¨β€πŸ¦²
    Bald,
}
impl Hair {
    /// Exhaustive list of all variants
    pub const ALL: [Hair; 6] = [
        Self::Beard,
        Self::Blond,
        Self::Red,
        Self::Curly,
        Self::White,
        Self::Bald,
    ];

    /// Descriptive name of this attribute variant
    pub const fn name(self) -> &'static str {
        match self {
            Self::Beard => "beard",
            Self::Bald => "no hair",
            Self::Blond => "blond hair",
            Self::Red => "red hair",
            Self::Curly => "curly hair",
            Self::White => "white hair",
        }
    }
}