use core::fmt;
use alloc::{
collections::BTreeSet,
string::{String, ToString},
vec::Vec,
};
#[derive(Clone, Debug, Default, Eq, Ord, PartialEq, PartialOrd)]
pub struct M2dirFlags(BTreeSet<String>);
impl M2dirFlags {
pub fn iter(&self) -> impl Iterator<Item = &str> {
self.0.iter().map(String::as_str)
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn insert(&mut self, flag: impl Into<String>) -> bool {
self.0.insert(flag.into())
}
pub fn remove(&mut self, flag: &str) -> bool {
self.0.remove(flag)
}
pub fn contains(&self, flag: &str) -> bool {
self.0.contains(flag)
}
pub fn extend(&mut self, flags: M2dirFlags) {
self.0.extend(flags.0);
}
pub fn difference(&mut self, flags: &M2dirFlags) {
self.0 = self.0.difference(&flags.0).cloned().collect();
}
pub fn to_meta(&self) -> String {
let mut out = String::new();
for flag in &self.0 {
out.push_str(flag);
out.push('\n');
}
out
}
pub fn from_meta(contents: &str) -> Self {
Self(
contents
.lines()
.filter(|line| !line.is_empty())
.map(ToString::to_string)
.collect(),
)
}
}
impl fmt::Display for M2dirFlags {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let sorted: Vec<&str> = self.0.iter().map(String::as_str).collect();
write!(f, "{}", sorted.join(","))
}
}
impl FromIterator<String> for M2dirFlags {
fn from_iter<I: IntoIterator<Item = String>>(iter: I) -> Self {
Self(iter.into_iter().collect())
}
}
impl<'a> FromIterator<&'a str> for M2dirFlags {
fn from_iter<I: IntoIterator<Item = &'a str>>(iter: I) -> Self {
Self(iter.into_iter().map(ToString::to_string).collect())
}
}
impl From<BTreeSet<String>> for M2dirFlags {
fn from(set: BTreeSet<String>) -> Self {
Self(set)
}
}
impl From<M2dirFlags> for BTreeSet<String> {
fn from(flags: M2dirFlags) -> Self {
flags.0
}
}
#[cfg(test)]
mod tests {
use crate::flag::types::*;
#[test]
fn meta_round_trip() {
let mut flags = M2dirFlags::default();
flags.insert("$seen");
flags.insert("$forwarded");
flags.insert("custom");
let serialized = flags.to_meta();
let parsed = M2dirFlags::from_meta(&serialized);
assert_eq!(parsed.len(), 3);
assert!(parsed.contains("$seen"));
assert!(parsed.contains("$forwarded"));
assert!(parsed.contains("custom"));
}
#[test]
fn meta_is_sorted() {
let mut flags = M2dirFlags::default();
flags.insert("zeta");
flags.insert("alpha");
flags.insert("middle");
assert_eq!(flags.to_meta(), "alpha\nmiddle\nzeta\n");
}
#[test]
fn from_meta_ignores_blanks() {
let parsed = M2dirFlags::from_meta("$seen\n\n\n$forwarded\n");
assert_eq!(parsed.len(), 2);
assert!(parsed.contains("$seen"));
assert!(parsed.contains("$forwarded"));
}
}