radicle: extend emoji support

Extend the ranges of emojis that are supported, listed
[below](#new-emojis-supported).

To ensure that single `char` emojis are supported, the `emojis` crate
is added as a dev dependency, using it to check that a `Reaction` can
be constructed for the two groups `SmileysAndEmotion` and
`PeopleAndBody`.

### New Emojis Supported

'🩵' 0x1FA75
'🩶' 0x1FA76
'🩷' 0x1FA77
'🫀' 0x1FAC0
'🫁' 0x1FAC1
'🫂' 0x1FAC2
'🫃' 0x1FAC3
'🫄' 0x1FAC4
'🫅' 0x1FAC5
'🫆' 0x1FAC6
'🫠' 0x1FAE0
'🫡' 0x1FAE1
'🫢' 0x1FAE2
'🫣' 0x1FAE3
'🫤' 0x1FAE4
'🫥' 0x1FAE5
'🫦' 0x1FAE6
'🫨' 0x1FAE8
'🫩' 0x1FAE9
'🫰' 0x1FAF0
'🫱' 0x1FAF1
'🫲' 0x1FAF2
'🫳' 0x1FAF3
'🫴' 0x1FAF4
'🫵' 0x1FAF5
'🫶' 0x1FAF6
'🫷' 0x1FAF7
'🫸' 0x1FAF8
This commit is contained in:
Fintan Halpenny 2025-02-13 10:05:44 +00:00
parent a9a4aac322
commit c2863c08ab
3 changed files with 92 additions and 26 deletions

28
Cargo.lock generated
View File

@ -638,6 +638,15 @@ dependencies = [
"zeroize",
]
[[package]]
name = "emojis"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99e1f1df1f181f2539bac8bf027d31ca5ffbf9e559e3f2d09413b9107b5c02f4"
dependencies = [
"phf",
]
[[package]]
name = "equivalent"
version = "1.0.1"
@ -1709,6 +1718,24 @@ version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
[[package]]
name = "phf"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078"
dependencies = [
"phf_shared",
]
[[package]]
name = "phf_shared"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5"
dependencies = [
"siphasher 1.0.1",
]
[[package]]
name = "pkcs1"
version = "0.7.5"
@ -1877,6 +1904,7 @@ dependencies = [
"colored",
"crossbeam-channel",
"cyphernet",
"emojis",
"fastrand",
"git2",
"libc",

View File

@ -69,6 +69,7 @@ default-features = false
optional = true
[dev-dependencies]
emojis = { version = "0.6" }
pretty_assertions = { version = "1.3.0" }
qcheck-macros = { version = "1", default-features = false }
qcheck = { version = "1", default-features = false }

View File

@ -91,12 +91,18 @@ impl Reaction {
pub fn new(emoji: char) -> Result<Self, ReactionError> {
let val = emoji as u32;
let emoticons = 0x1F600..=0x1F64F;
let hearts = 0x1FA75..=0x1FA77;
let body_update = 0x1FAC0..=0x1FAC6;
let emoticons_update = 0x1FAE0..=0x1FAF8;
let misc = 0x1F300..=0x1F5FF; // Miscellaneous Symbols and Pictographs
let dingbats = 0x2700..=0x27BF;
let supp = 0x1F900..=0x1F9FF; // Supplemental Symbols and Pictographs
let transport = 0x1F680..=0x1F6FF;
if emoticons.contains(&val)
|| hearts.contains(&val)
|| body_update.contains(&val)
|| emoticons_update.contains(&val)
|| misc.contains(&val)
|| dingbats.contains(&val)
|| supp.contains(&val)
@ -367,32 +373,6 @@ impl From<bool> for Authorization {
}
}
#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod test {
use super::*;
#[test]
fn test_color() {
let c = Color::from_str("#ffccaa").unwrap();
assert_eq!(c.to_string(), "#ffccaa".to_owned());
assert_eq!(serde_json::to_string(&c).unwrap(), "\"#ffccaa\"".to_owned());
assert_eq!(serde_json::from_str::<'_, Color>("\"#ffccaa\"").unwrap(), c);
let c = Color::from_str("#0000aa").unwrap();
assert_eq!(c.to_string(), "#0000aa".to_owned());
let c = Color::from_str("#aa0000").unwrap();
assert_eq!(c.to_string(), "#aa0000".to_owned());
let c = Color::from_str("#00aa00").unwrap();
assert_eq!(c.to_string(), "#00aa00".to_owned());
Color::from_str("#aa00").unwrap_err();
Color::from_str("#abc").unwrap_err();
}
}
/// Describes a code location that can be used for comments on
/// patches, issues, and diffs.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
@ -446,3 +426,60 @@ impl std::cmp::Ord for CodeRange {
}
}
}
#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod test {
use std::collections::BTreeSet;
use super::*;
#[test]
fn test_color() {
let c = Color::from_str("#ffccaa").unwrap();
assert_eq!(c.to_string(), "#ffccaa".to_owned());
assert_eq!(serde_json::to_string(&c).unwrap(), "\"#ffccaa\"".to_owned());
assert_eq!(serde_json::from_str::<'_, Color>("\"#ffccaa\"").unwrap(), c);
let c = Color::from_str("#0000aa").unwrap();
assert_eq!(c.to_string(), "#0000aa".to_owned());
let c = Color::from_str("#aa0000").unwrap();
assert_eq!(c.to_string(), "#aa0000".to_owned());
let c = Color::from_str("#00aa00").unwrap();
assert_eq!(c.to_string(), "#00aa00".to_owned());
Color::from_str("#aa00").unwrap_err();
Color::from_str("#abc").unwrap_err();
}
#[test]
fn test_emojis() {
let emojis = emojis::Group::SmileysAndEmotion
.emojis()
.chain(emojis::Group::PeopleAndBody.emojis())
.filter_map(|emoji| {
if emoji.as_str().chars().count() == 1 {
Some(emoji.as_str().chars().next().unwrap())
} else {
None
}
});
let mut failed = BTreeSet::new();
for emoji in emojis {
if Reaction::new(emoji).is_err() {
failed.insert(emoji);
}
}
if !failed.is_empty() {
for emoji in failed {
eprintln!(
"cannot construct Reaction for '{emoji}' {:#04X}",
(emoji as u32)
);
}
panic!("Failed to construct Reaction for these emojis");
}
}
}