use im::OrdMap; use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer}; use crate::bayou::*; type ImapUid = u32; type ImapUidvalidity = u32; /// A Mail UUID is composed of two components: /// - a process identifier, 128 bits /// - a sequence number, 64 bits #[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq)] pub struct MailUuid(pub [u8; 24]); #[derive(Clone)] pub struct UidIndex { mail_uid: OrdMap, mail_flags: OrdMap>, mails_by_uid: OrdMap, uidvalidity: ImapUidvalidity, uidnext: ImapUid, internalseq: ImapUid, } #[derive(Clone, Serialize, Deserialize)] pub enum UidIndexOp { MailAdd(MailUuid, ImapUid, Vec), MailDel(MailUuid), } impl Default for UidIndex { fn default() -> Self { Self { mail_flags: OrdMap::new(), mail_uid: OrdMap::new(), mails_by_uid: OrdMap::new(), uidvalidity: 1, uidnext: 1, internalseq: 1, } } } impl BayouState for UidIndex { type Op = UidIndexOp; fn apply(&self, op: &UidIndexOp) -> Self { let mut new = self.clone(); match op { UidIndexOp::MailAdd(uuid, uid, flags) => { if *uid < new.internalseq { new.uidvalidity += new.internalseq - *uid; } let new_uid = new.internalseq; if let Some(prev_uid) = new.mail_uid.get(uuid) { new.mails_by_uid.remove(prev_uid); } else { new.mail_flags.insert(*uuid, flags.clone()); } new.mails_by_uid.insert(new_uid, *uuid); new.mail_uid.insert(*uuid, new_uid); new.internalseq += 1; new.uidnext = new.internalseq; } UidIndexOp::MailDel(uuid) => { if let Some(uid) = new.mail_uid.get(uuid) { new.mails_by_uid.remove(uid); new.mail_uid.remove(uuid); new.mail_flags.remove(uuid); } new.internalseq += 1; } } new } } // ---- CUSTOM SERIALIZATION AND DESERIALIZATION ---- #[derive(Serialize, Deserialize)] struct UidIndexSerializedRepr { mails: Vec<(ImapUid, MailUuid, Vec)>, uidvalidity: ImapUidvalidity, uidnext: ImapUid, internalseq: ImapUid, } impl<'de> Deserialize<'de> for UidIndex { fn deserialize(d: D) -> Result where D: Deserializer<'de>, { let val: UidIndexSerializedRepr = UidIndexSerializedRepr::deserialize(d)?; let mut uidindex = UidIndex { mail_flags: OrdMap::new(), mail_uid: OrdMap::new(), mails_by_uid: OrdMap::new(), uidvalidity: val.uidvalidity, uidnext: val.uidnext, internalseq: val.internalseq, }; for (uid, uuid, flags) in val.mails { uidindex.mail_flags.insert(uuid, flags); uidindex.mail_uid.insert(uuid, uid); uidindex.mails_by_uid.insert(uid, uuid); } Ok(uidindex) } } impl Serialize for UidIndex { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut mails = vec![]; for (uid, uuid) in self.mails_by_uid.iter() { mails.push(( *uid, *uuid, self.mail_flags.get(uuid).cloned().unwrap_or_default(), )); } let val = UidIndexSerializedRepr { mails, uidvalidity: self.uidvalidity, uidnext: self.uidnext, internalseq: self.internalseq, }; val.serialize(serializer) } } impl<'de> Deserialize<'de> for MailUuid { fn deserialize(d: D) -> Result where D: Deserializer<'de>, { let v = String::deserialize(d)?; let bytes = hex::decode(v).map_err(|_| D::Error::custom("invalid hex"))?; if bytes.len() != 24 { return Err(D::Error::custom("bad length")); } let mut tmp = [0u8; 24]; tmp[..].copy_from_slice(&bytes); Ok(Self(tmp)) } } impl Serialize for MailUuid { fn serialize(&self, serializer: S) -> Result where S: Serializer, { serializer.serialize_str(&hex::encode(self.0)) } }