vomit-sync 0.10.1

A library for IMAP to maildir synchronization
Documentation
use std::collections::BTreeSet;
use std::fmt;

pub struct SeqSet {
    set: BTreeSet<u32>,
}

impl SeqSet {
    pub fn new() -> Self {
        SeqSet {
            set: BTreeSet::new(),
        }
    }
}

impl std::ops::Deref for SeqSet {
    type Target = BTreeSet<u32>;
    fn deref(&self) -> &Self::Target {
        &self.set
    }
}

impl std::ops::DerefMut for SeqSet {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.set
    }
}

impl<const N: usize> std::convert::From<[u32; N]> for SeqSet {
    fn from(arr: [u32; N]) -> Self {
        SeqSet {
            set: BTreeSet::from(arr),
        }
    }
}

impl std::convert::From<&BTreeSet<u32>> for SeqSet {
    fn from(set: &BTreeSet<u32>) -> Self {
        SeqSet { set: set.clone() }
    }
}

impl FromIterator<u32> for SeqSet {
    fn from_iter<T: IntoIterator<Item = u32>>(iter: T) -> Self {
        let mut set = BTreeSet::new();
        for i in iter {
            set.insert(i);
        }
        SeqSet { set }
    }
}

impl fmt::Display for SeqSet {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let mut is_range = false;
        let mut last: u32 = 0;

        for id in &self.set {
            if last == 0 {
                write!(f, "{}", id)?;
            } else if *id == u32::MAX {
                // Special notation for :*
                // It's the users responsibility to make sure this is being used correctly
                write!(f, ":*")?;
            } else if *id == (last + 1) {
                is_range = true;
            } else {
                if is_range {
                    write!(f, ":{},{}", last, *id)?;
                } else {
                    write!(f, ",{}", *id)?;
                }
                is_range = false;
            }
            last = *id;
        }
        if is_range {
            write!(f, ":{}", last)?;
        }
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_seq_set() {
        let set = SeqSet::from([1]);
        assert_eq!(set.to_string(), String::from("1"));

        let set = SeqSet::from([1, 2]);
        assert_eq!(set.to_string(), String::from("1:2"));

        let set = SeqSet::from([1, 3]);
        assert_eq!(set.to_string(), String::from("1,3"));

        let set = SeqSet::from([1, 3, 4, 5, 19]);
        assert_eq!(set.to_string(), String::from("1,3:5,19"));

        let set = SeqSet::from([1, 2, 3, 4, 6, 8, 10, 11, 12]);
        assert_eq!(set.to_string(), String::from("1:4,6,8,10:12"));

        let set = SeqSet::from([1, 3, 2, 10, 6, 8, 10, 4, 11, 12]);
        assert_eq!(set.to_string(), String::from("1:4,6,8,10:12"));

        let set = SeqSet::from([1, u32::MAX]);
        assert_eq!(set.to_string(), String::from("1:*"));
    }
}