radicle: safe Reaction construction

The Reaction type needs to ensure that the `char` stored for its value
meets certain requirements -- via its `new` constructor.

To ensure Reaction is always constructed correctly, the `pub` accessor
is removed, and the Deserialize implementation is implemented by hand
-- as opposed to using derive.

Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>
X-Clacks-Overhead: GNU Terry Pratchett
This commit is contained in:
Fintan Halpenny 2023-03-13 16:11:58 +00:00 committed by Alexis Sellier
parent 0337574750
commit de8e92d48c
No known key found for this signature in database
1 changed files with 42 additions and 2 deletions

View File

@ -36,10 +36,10 @@ pub enum ReactionError {
InvalidReaction,
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Clone, Serialize, Deserialize)]
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Clone, Serialize)]
#[serde(transparent)]
pub struct Reaction {
pub emoji: char,
emoji: char,
}
impl Reaction {
@ -51,6 +51,46 @@ impl Reaction {
}
}
impl<'de> Deserialize<'de> for Reaction {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
struct ReactionVisitor;
impl<'de> serde::de::Visitor<'de> for ReactionVisitor {
type Value = Reaction;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a reaction emoji")
}
fn visit_char<E>(self, v: char) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Reaction::new(v).map_err(|e| E::custom(e.to_string()))
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Reaction::from_str(v).map_err(|e| E::custom(e.to_string()))
}
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Reaction::from_str(&v).map_err(|e| E::custom(e.to_string()))
}
}
deserializer.deserialize_char(ReactionVisitor)
}
}
impl FromStr for Reaction {
type Err = ReactionError;