use anyhow::{anyhow, Error, Result};
use serde::ser::{Serialize, SerializeSeq, Serializer};
use std::{
borrow::Cow,
collections::HashSet,
convert::{TryFrom, TryInto},
fmt::{self, Display},
ops::{Deref, DerefMut},
};
use crate::domain::msg::{Flag, SerializableFlag};
#[derive(Debug, Clone, Default)]
pub struct Flags(pub HashSet<Flag<'static>>);
impl Flags {
pub fn to_symbols_string(&self) -> String {
let mut flags = String::new();
flags.push_str(if self.contains(&Flag::Seen) {
" "
} else {
"✷"
});
flags.push_str(if self.contains(&Flag::Answered) {
"↵"
} else {
" "
});
flags.push_str(if self.contains(&Flag::Flagged) {
"⚑"
} else {
" "
});
flags
}
}
impl Display for Flags {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut glue = "";
for flag in &self.0 {
write!(f, "{}", glue)?;
match flag {
Flag::Seen => write!(f, "\\Seen")?,
Flag::Answered => write!(f, "\\Answered")?,
Flag::Flagged => write!(f, "\\Flagged")?,
Flag::Deleted => write!(f, "\\Deleted")?,
Flag::Draft => write!(f, "\\Draft")?,
Flag::Recent => write!(f, "\\Recent")?,
Flag::MayCreate => write!(f, "\\MayCreate")?,
Flag::Custom(cow) => write!(f, "{}", cow)?,
_ => (),
}
glue = " ";
}
Ok(())
}
}
impl<'a> TryFrom<Vec<Flag<'a>>> for Flags {
type Error = Error;
fn try_from(flags: Vec<Flag<'a>>) -> Result<Flags> {
let mut set: HashSet<Flag<'static>> = HashSet::new();
for flag in flags {
set.insert(match flag {
Flag::Seen => Flag::Seen,
Flag::Answered => Flag::Answered,
Flag::Flagged => Flag::Flagged,
Flag::Deleted => Flag::Deleted,
Flag::Draft => Flag::Draft,
Flag::Recent => Flag::Recent,
Flag::MayCreate => Flag::MayCreate,
Flag::Custom(cow) => Flag::Custom(Cow::Owned(cow.to_string())),
flag => return Err(anyhow!(r#"cannot parse flag "{}""#, flag)),
});
}
Ok(Self(set))
}
}
impl<'a> TryFrom<&'a [Flag<'a>]> for Flags {
type Error = Error;
fn try_from(flags: &'a [Flag<'a>]) -> Result<Flags> {
flags.to_vec().try_into()
}
}
impl Deref for Flags {
type Target = HashSet<Flag<'static>>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for Flags {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl Serialize for Flags {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut seq = serializer.serialize_seq(Some(self.0.len()))?;
for flag in &self.0 {
seq.serialize_element(&SerializableFlag(flag))?;
}
seq.end()
}
}
impl<'a> From<Vec<&'a str>> for Flags {
fn from(flags: Vec<&'a str>) -> Self {
let mut map: HashSet<Flag<'static>> = HashSet::new();
for f in flags {
match f.to_lowercase().as_str() {
"answered" => map.insert(Flag::Answered),
"deleted" => map.insert(Flag::Deleted),
"draft" => map.insert(Flag::Draft),
"flagged" => map.insert(Flag::Flagged),
"maycreate" => map.insert(Flag::MayCreate),
"recent" => map.insert(Flag::Recent),
"seen" => map.insert(Flag::Seen),
custom => map.insert(Flag::Custom(Cow::Owned(custom.into()))),
};
}
Self(map)
}
}