use super::super::EventErr; use serde::{ de::{self, Visitor}, Deserialize, Deserializer, Serialize, Serializer, }; use serde_json::Value; use std::{convert::TryFrom, fmt, num::ParseIntError, str::FromStr}; /// A user ID. /// /// Internally, Mastodon IDs are i64s, but are sent to clients as string because /// JavaScript numbers don't support i64s. This newtype serializes to/from a string, but /// keeps the i64 as the "true" value for internal use. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct Id(pub i64); impl TryFrom<&Value> for Id { type Error = EventErr; fn try_from(v: &Value) -> Result { Ok(v.as_str().ok_or(EventErr::DynParse)?.parse()?) } } impl std::ops::Deref for Id { type Target = i64; fn deref(&self) -> &i64 { &self.0 } } impl FromStr for Id { type Err = ParseIntError; fn from_str(s: &str) -> Result { Ok(Self(s.parse()?)) } } impl fmt::Display for Id { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { write!(f, "{}", self.0) } } impl Serialize for Id { fn serialize(&self, serializer: S) -> Result where S: Serializer, { serializer.serialize_str(&format!("{}", self.0)) } } impl<'de> Deserialize<'de> for Id { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { deserializer.deserialize_string(IdVisitor) } } struct IdVisitor; impl<'de> Visitor<'de> for IdVisitor { type Value = Id; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("a string that can be parsed into an i64") } fn visit_str(self, value: &str) -> Result { match value.parse() { Ok(n) => Ok(Id(n)), Err(e) => Err(E::custom(format!("could not parse: {}", e))), } } fn visit_string(self, value: String) -> Result { match value.parse() { Ok(n) => Ok(Id(n)), Err(e) => Err(E::custom(format!("could not parse: {}", e))), } } }