use std::borrow::Cow;
use serde::{Deserialize, Serialize};
use crate::{impl_default, impl_display, Error, Result};
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
#[serde(untagged)]
pub enum MessageTo {
ChannelId(u64),
ChannelName(String),
UserIds(Vec<u64>),
UserEmails(Vec<String>),
}
impl MessageTo {
pub const CHANNEL_ID_FIELD: &str = "channel_id";
pub const CHANNEL_NAME_FIELD: &str = "channel_name";
pub const USER_IDS_FIELD: &str = "user_ids";
pub const USER_EMAILS_FIELD: &str = "user_emails";
pub const fn new() -> Self {
Self::ChannelId(0)
}
pub const fn field_name(&self) -> &'static str {
match self {
Self::ChannelId(_) => Self::CHANNEL_ID_FIELD,
Self::ChannelName(_) => Self::CHANNEL_NAME_FIELD,
Self::UserIds(_) => Self::USER_IDS_FIELD,
Self::UserEmails(_) => Self::USER_EMAILS_FIELD,
}
}
pub const fn channel_id(val: u64) -> Self {
Self::ChannelId(val)
}
pub fn as_channel_id(&self) -> Result<u64> {
match self {
Self::ChannelId(n) => Ok(*n),
_ => Err(Error::invalid_field(
"message to",
self.field_name(),
Self::CHANNEL_ID_FIELD,
)),
}
}
pub fn channel_name<'c, C: Into<Cow<'c, str>>>(val: C) -> Self {
Self::ChannelName(C::into(val).into())
}
pub fn as_channel_name(&self) -> Result<&str> {
match self {
Self::ChannelName(n) => Ok(n.as_str()),
_ => Err(Error::invalid_field(
"message to",
self.field_name(),
Self::CHANNEL_NAME_FIELD,
)),
}
}
pub fn user_ids<'c, C: Into<Cow<'c, [u64]>>>(val: C) -> Self {
Self::UserIds(C::into(val).into())
}
pub fn as_user_ids(&self) -> Result<&[u64]> {
match self {
Self::UserIds(n) => Ok(n.as_ref()),
_ => Err(Error::invalid_field(
"message to",
self.field_name(),
Self::USER_IDS_FIELD,
)),
}
}
pub fn user_emails<'c, C: Into<Cow<'c, [String]>>>(val: C) -> Self {
Self::UserEmails(C::into(val).into())
}
pub fn as_user_emails(&self) -> Result<&[String]> {
match self {
Self::UserEmails(n) => Ok(n.as_ref()),
_ => Err(Error::invalid_field(
"message to",
self.field_name(),
Self::USER_EMAILS_FIELD,
)),
}
}
pub fn as_string(&self) -> String {
serde_json::to_string(&self)
.ok()
.and_then(|s| {
s.strip_prefix("\"")
.and_then(|v| v.strip_suffix("\"").map(String::from))
})
.unwrap_or_default()
}
}
impl_default!(MessageTo);
impl_display!(MessageTo);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_message_to_channel_name() {
let chan_name = String::from("#test");
let chan_name_json = format!(r#""{chan_name}""#);
let to_chan_name = MessageTo::ChannelName(chan_name.clone());
assert_eq!(
serde_json::to_string(&to_chan_name).unwrap().as_str(),
chan_name_json
);
assert_eq!(
serde_json::from_str::<MessageTo>(chan_name_json.as_str()).unwrap(),
to_chan_name
);
assert_eq!(to_chan_name.as_channel_name(), Ok(chan_name.as_str()));
}
#[test]
fn test_message_to_user_emails() {
let user_emails = vec![String::from("test@example.com")];
let user_emails_json = format!(r#"["{}"]"#, user_emails[0]);
let to_user_emails = MessageTo::UserEmails(user_emails.clone());
assert_eq!(
serde_json::to_string(&to_user_emails).unwrap().as_str(),
user_emails_json
);
assert_eq!(
serde_json::from_str::<MessageTo>(user_emails_json.as_str()).unwrap(),
to_user_emails
);
assert_eq!(to_user_emails.as_user_emails(), Ok(user_emails.as_slice()));
}
#[test]
fn test_message_to_channel_id() {
(0..=u64::BITS)
.map(|r| ((1u128 << r) - 1) as u64)
.for_each(|id| {
let chan_id_json = format!("{id}");
let to_chan_id = MessageTo::ChannelId(id);
assert_eq!(
serde_json::to_string(&to_chan_id).unwrap().as_str(),
chan_id_json
);
assert_eq!(
serde_json::from_str::<MessageTo>(chan_id_json.as_str()).unwrap(),
to_chan_id
);
assert_eq!(to_chan_id.as_channel_id(), Ok(id));
});
}
#[test]
fn test_message_to_user_ids() {
(0..=u64::BITS)
.map(|r| ((1u128 << r) - 1) as u64)
.for_each(|id| {
let user_ids = vec![id];
let user_ids_json = format!("[{id}]");
let to_user_ids = MessageTo::UserIds(user_ids.clone());
assert_eq!(
serde_json::to_string(&to_user_ids).unwrap().as_str(),
user_ids_json
);
assert_eq!(
serde_json::from_str::<MessageTo>(user_ids_json.as_str()).unwrap(),
to_user_ids
);
assert_eq!(to_user_ids.as_user_ids(), Ok(user_ids.as_slice()));
});
}
}