use super::Resolver;
use crate::store::AddressEntry;
use std::fmt;
#[derive(Clone, Copy)]
pub struct AddressList<'m> {
resolver: Resolver<'m>,
items: &'m [AddressEntry],
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Address<'m> {
Mailbox(Mailbox<'m>),
Group(Group<'m>),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Mailbox<'m> {
name: Option<&'m str>,
address: Option<&'m str>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Group<'m> {
name: Option<&'m str>,
members: AddressRun<'m>,
}
#[derive(Clone, Copy)]
pub struct AddressRun<'m> {
resolver: Resolver<'m>,
items: &'m [AddressEntry],
}
impl fmt::Debug for AddressList<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.iter()).finish()
}
}
impl fmt::Debug for AddressRun<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(*self).finish()
}
}
impl PartialEq for AddressList<'_> {
fn eq(&self, other: &Self) -> bool {
self.items.len() == other.items.len() && self.iter().eq(other.iter())
}
}
impl Eq for AddressList<'_> {}
impl PartialEq for AddressRun<'_> {
fn eq(&self, other: &Self) -> bool {
self.items.len() == other.items.len() && Iterator::eq(*self, *other)
}
}
impl Eq for AddressRun<'_> {}
impl<'m> Resolver<'m> {
fn mailbox(self, entry: &AddressEntry) -> Mailbox<'m> {
Mailbox {
name: self.opt(entry.name),
address: self.opt(entry.address),
}
}
}
impl<'m> AddressList<'m> {
pub(crate) fn new(resolver: Resolver<'m>, items: &'m [AddressEntry]) -> Self {
AddressList { resolver, items }
}
pub fn is_empty(&self) -> bool {
self.items.is_empty()
}
pub fn iter(&self) -> impl Iterator<Item = Address<'m>> + use<'m> {
let resolver = self.resolver;
let mut rest = self.items;
std::iter::from_fn(move || {
let (first, tail) = rest.split_first()?;
if first.is_group() {
let (members, tail) = tail.split_at(first.members().min(tail.len()));
rest = tail;
Some(Address::Group(Group {
name: resolver.opt(first.name),
members: AddressRun {
resolver,
items: members,
},
}))
} else {
rest = tail;
Some(Address::Mailbox(resolver.mailbox(first)))
}
})
}
pub fn mailboxes(&self) -> impl DoubleEndedIterator<Item = Mailbox<'m>> + use<'m> {
let resolver = self.resolver;
self.items
.iter()
.filter(|entry| !entry.is_group())
.map(move |entry| resolver.mailbox(entry))
}
pub fn first(&self) -> Option<Mailbox<'m>> {
self.mailboxes().next()
}
pub fn last(&self) -> Option<Mailbox<'m>> {
self.mailboxes().next_back()
}
pub fn groups(&self) -> impl Iterator<Item = (Option<&'m str>, AddressRun<'m>)> + use<'m> {
let resolver = self.resolver;
let mut rest = self.items;
std::iter::from_fn(move || {
let (first, tail) = rest.split_first()?;
let (name, run, tail) = if first.is_group() {
let (members, tail) = tail.split_at(first.members().min(tail.len()));
(resolver.opt(first.name), members, tail)
} else {
let len = rest.iter().take_while(|entry| !entry.is_group()).count();
let (run, tail) = rest.split_at(len);
(None, run, tail)
};
rest = tail;
Some((
name,
AddressRun {
resolver,
items: run,
},
))
})
}
pub fn contains(&self, address: &str) -> bool {
self.mailboxes().any(|mailbox| {
mailbox
.address
.is_some_and(|a| a.eq_ignore_ascii_case(address))
})
}
pub fn has_groups(&self) -> bool {
self.items.iter().any(AddressEntry::is_group)
}
}
impl<'m> Mailbox<'m> {
pub fn name(&self) -> Option<&'m str> {
self.name
}
pub fn address(&self) -> Option<&'m str> {
self.address
}
}
impl<'m> Group<'m> {
pub fn name(&self) -> Option<&'m str> {
self.name
}
pub fn mailboxes(&self) -> AddressRun<'m> {
self.members
}
pub fn len(&self) -> usize {
self.members.len()
}
pub fn is_empty(&self) -> bool {
self.members.len() == 0
}
}
impl<'m> Iterator for AddressRun<'m> {
type Item = Mailbox<'m>;
fn next(&mut self) -> Option<Mailbox<'m>> {
let (first, rest) = self.items.split_first()?;
self.items = rest;
Some(self.resolver.mailbox(first))
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.items.len(), Some(self.items.len()))
}
}
impl DoubleEndedIterator for AddressRun<'_> {
fn next_back(&mut self) -> Option<Self::Item> {
let (last, rest) = self.items.split_last()?;
self.items = rest;
Some(self.resolver.mailbox(last))
}
}
impl ExactSizeIterator for AddressRun<'_> {}