pub mod events;
use crate::Error;
use serde::Deserialize;
use std::{convert::TryFrom, fmt};
pub type UserId = crate::types::Snowflake;
#[derive(Clone)]
pub struct Avatar(pub [u8; 16]);
impl Avatar {
pub(crate) fn from_str(ava_str: &str) -> Option<Self> {
let avatar = ava_str.strip_prefix("a_").unwrap_or(ava_str);
if avatar.len() != 32 {
None
} else {
let mut md5 = [0u8; 16];
for (ind, exp) in avatar.as_bytes().chunks(2).enumerate() {
let mut cur = match exp[0] {
b'A'..=b'F' => exp[0] - b'A' + 10,
b'a'..=b'f' => exp[0] - b'a' + 10,
b'0'..=b'9' => exp[0] - b'0',
c => {
tracing::debug!("invalid character '{}' found in avatar", c);
return None;
}
};
cur <<= 4;
cur |= match exp[1] {
b'A'..=b'F' => exp[1] - b'A' + 10,
b'a'..=b'f' => exp[1] - b'a' + 10,
b'0'..=b'9' => exp[1] - b'0',
c => {
tracing::debug!("invalid character '{}' found in avatar", c);
return None;
}
};
md5[ind] = cur;
}
Some(Self(md5))
}
}
}
#[cfg(test)]
impl serde::Serialize for Avatar {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::ser::Serializer,
{
use std::fmt::Write;
let mut hex_str = String::with_capacity(32);
for byte in self.0 {
let _ = write!(&mut hex_str, "{:02x}", byte);
}
serializer.serialize_str(&hex_str)
}
}
#[derive(Clone)]
pub struct User {
pub id: UserId,
pub username: String,
pub discriminator: Option<u32>,
pub avatar: Option<Avatar>,
pub is_bot: bool,
}
impl<'de> Deserialize<'de> for User {
fn deserialize<D>(d: D) -> Result<Self, D::Error>
where
D: serde::de::Deserializer<'de>,
{
let u: DeUser<'de> = serde::de::Deserialize::deserialize(d)?;
Self::try_from(u).map_err(serde::de::Error::custom)
}
}
#[cfg(test)]
impl serde::Serialize for User {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::ser::Serializer,
{
use serde::ser::SerializeStruct;
let mut state = serializer.serialize_struct("User", 5)?;
state.serialize_field("id", &self.id)?;
state.serialize_field("username", &self.username)?;
state.serialize_field(
"discriminator",
&self.discriminator.unwrap_or_default().to_string(),
)?;
state.serialize_field("avatar", &self.avatar)?;
state.serialize_field("bot", &self.is_bot)?;
state.end()
}
}
impl fmt::Debug for User {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("User")
.field("id", &self.id)
.field("username", &self.username)
.field("discriminator", &self.discriminator)
.finish()
}
}
impl fmt::Display for User {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.username)?;
if let Some(disc) = self.discriminator {
write!(f, "#{}", disc)?;
}
Ok(())
}
}
#[derive(Deserialize)]
struct DeUser<'u> {
id: Option<UserId>,
username: Option<&'u str>,
discriminator: Option<&'u str>,
avatar: Option<&'u str>,
bot: Option<bool>,
}
impl<'de> TryFrom<DeUser<'de>> for User {
type Error = Error;
fn try_from(u: DeUser<'de>) -> Result<Self, Self::Error> {
let id = u.id.ok_or(Error::MissingField("id"))?;
let username = u
.username
.ok_or(Error::MissingField("username"))?
.to_owned();
let discriminator = match u.discriminator {
Some(d) => Some(
d.parse()
.map_err(|_err| Error::InvalidField("discriminator"))?,
),
None => None,
};
let avatar = match u.avatar {
Some(a) => Avatar::from_str(a),
None => None,
};
Ok(Self {
id,
username,
discriminator,
avatar,
is_bot: u.bot.unwrap_or(false),
})
}
}