Skip to content

Commit

Permalink
Add serde support for types
Browse files Browse the repository at this point in the history
  • Loading branch information
rossmacarthur committed Jul 24, 2024
1 parent 3cb635d commit 2c79383
Show file tree
Hide file tree
Showing 7 changed files with 220 additions and 14 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
/target
/.vscode
111 changes: 97 additions & 14 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,11 @@ members = ["generate"]

[dependencies]
phf = { version = "0.11.1", default-features = false }
serde = { version = "1.0.124", default-features = false, features = ["derive"], optional = true }

[dev-dependencies]
serde_json = "1.0.120"
toml = "0.8.15"

[features]
serde = ["dep:serde"]
4 changes: 4 additions & 0 deletions generate/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ fn write_group_enum<W: io::Write>(w: &mut W, unicode_data: &unicode::ParsedData)
w,
"#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]"
)?;
writeln!(
w,
r#"#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]"#,
)?;
writeln!(w, "pub enum Group {{")?;
for name in unicode_data.keys() {
if name == "Component" {
Expand Down
1 change: 1 addition & 0 deletions src/gen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use crate::{Emoji, SkinTone, UnicodeVersion};
///
/// Based on Unicode CLDR data.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Group {
SmileysAndEmotion,
PeopleAndBody,
Expand Down
39 changes: 39 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,13 +139,15 @@ pub struct Emoji {

/// A Unicode version.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct UnicodeVersion {
major: u32,
minor: u32,
}

/// The skin tone of an emoji.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[non_exhaustive]
pub enum SkinTone {
Default,
Expand Down Expand Up @@ -459,6 +461,43 @@ impl fmt::Display for Emoji {
}
}

#[cfg(feature = "serde")]
impl serde::Serialize for &'static Emoji {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(self.as_str())
}
}

#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for &'static Emoji {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
struct Visitor;

impl<'de> serde::de::Visitor<'de> for Visitor {
type Value = &'static Emoji;

fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
formatter.write_str("a string representing an emoji")
}

fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
crate::get(value).ok_or_else(|| E::custom("invalid emoji"))
}
}

deserializer.deserialize_str(Visitor)
}
}

impl Group {
/// Returns an iterator over all groups.
///
Expand Down
70 changes: 70 additions & 0 deletions tests/serde.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#![cfg(feature = "serde")]

use emojis::{Emoji, Group, SkinTone, UnicodeVersion};
use serde::{Deserialize, Serialize};

#[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
struct Test {
version: UnicodeVersion,
skin_tone: SkinTone,
group: Group,
emoji: &'static Emoji,
}

#[test]
fn test_serialize_roundtrip_json() {
let test = Test {
emoji: emojis::get("🚀").unwrap(),
version: UnicodeVersion::new(13, 0),
skin_tone: SkinTone::Default,
group: Group::Activities,
};
let serialized = serde_json::to_string_pretty(&test).unwrap();
assert_eq!(
serialized,
r#"{
"version": {
"major": 13,
"minor": 0
},
"skin_tone": "Default",
"group": "Activities",
"emoji": "🚀"
}"#
);
let deserialized: Test = serde_json::from_str(&serialized).unwrap();

assert_eq!(deserialized, test);
}

#[test]
fn test_serialize_roundtrip_toml() {
let test = Test {
emoji: emojis::get("🚀").unwrap(),
version: UnicodeVersion::new(13, 0),
skin_tone: SkinTone::Default,
group: Group::Activities,
};
let serialized = toml::to_string(&test).unwrap();
assert_eq!(
serialized,
r#"skin_tone = "Default"
group = "Activities"
emoji = "🚀"
[version]
major = 13
minor = 0
"#
);

let deserialized: Test = toml::from_str(&serialized).unwrap();

assert_eq!(deserialized, test);
}

#[test]
fn emoji_deserialize_invalid() {
let err = serde_json::from_str::<Test>(r#"{"emoji":"invalid"}"#).unwrap_err();
assert_eq!(err.to_string(), "invalid emoji at line 1 column 18");
}

0 comments on commit 2c79383

Please sign in to comment.