diff --git a/src/mailbox.rs b/src/mailbox.rs index 9d6c1fc..43ff5ca 100644 --- a/src/mailbox.rs +++ b/src/mailbox.rs @@ -69,7 +69,7 @@ impl Mailbox { let add_mail_op = self .uid_index .state() - .op_mail_add(MailUuid(rand_id), vec!["\\Unseen".into()]); + .op_mail_add(MailIdent(rand_id), vec!["\\Unseen".into()]); self.uid_index.push(add_mail_op).await?; dump(&self.uid_index); diff --git a/src/uidindex.rs b/src/uidindex.rs index bcc5ecd..903690c 100644 --- a/src/uidindex.rs +++ b/src/uidindex.rs @@ -1,4 +1,4 @@ -use im::{HashMap, HashSet, OrdMap}; +use im::{HashMap, HashSet, OrdSet, OrdMap}; use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer}; use crate::bayou::*; @@ -7,11 +7,15 @@ pub type ImapUid = u32; pub type ImapUidvalidity = u32; pub type Flag = String; -/// A Mail UUID is composed of two components: +/// Mail Identifier (MailIdent) are composed of two components: /// - a process identifier, 128 bits /// - a sequence number, 64 bits +/// They are not part of the protocol but an internal representation +/// required by Mailrage/Aerogramme. +/// Their main property is to be unique without having to rely +/// on synchronization between IMAP processes. #[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash, Debug)] -pub struct MailUuid(pub [u8; 24]); +pub struct MailIdent(pub [u8; 24]); #[derive(Clone)] /// A UidIndex handles the mutable part of a mailbox @@ -20,10 +24,10 @@ pub struct MailUuid(pub [u8; 24]); /// and applying the event. This is why we use immutable datastructures /// that are optimized for cloning (they clone underlying values only if they are modified) pub struct UidIndex { - pub mail_uid: OrdMap, - pub mail_flags: OrdMap>, - pub mails_by_uid: OrdMap, - pub flags: HashMap>, + pub mail_uid: OrdMap, + pub mail_flags: OrdMap>, + pub mails_by_uid: OrdMap, + pub flags: HashMap>, pub uidvalidity: ImapUidvalidity, pub uidnext: ImapUid, @@ -32,31 +36,31 @@ pub struct UidIndex { #[derive(Clone, Serialize, Deserialize, Debug)] pub enum UidIndexOp { - MailAdd(MailUuid, ImapUid, Vec), - MailDel(MailUuid), - FlagAdd(MailUuid, Vec), - FlagDel(MailUuid, Vec), + MailAdd(MailIdent, ImapUid, Vec), + MailDel(MailIdent), + FlagAdd(MailIdent, Vec), + FlagDel(MailIdent, Vec), } impl UidIndex { #[must_use] - pub fn op_mail_add(&self, uuid: MailUuid, flags: Vec) -> UidIndexOp { - UidIndexOp::MailAdd(uuid, self.internalseq, flags) + pub fn op_mail_add(&self, ident: MailIdent, flags: Vec) -> UidIndexOp { + UidIndexOp::MailAdd(ident, self.internalseq, flags) } #[must_use] - pub fn op_mail_del(&self, uuid: MailUuid) -> UidIndexOp { - UidIndexOp::MailDel(uuid) + pub fn op_mail_del(&self, ident: MailIdent) -> UidIndexOp { + UidIndexOp::MailDel(ident) } #[must_use] - pub fn op_flag_add(&self, uuid: MailUuid, flags: Vec) -> UidIndexOp { - UidIndexOp::FlagAdd(uuid, flags) + pub fn op_flag_add(&self, ident: MailIdent, flags: Vec) -> UidIndexOp { + UidIndexOp::FlagAdd(ident, flags) } #[must_use] - pub fn op_flag_del(&self, uuid: MailUuid, flags: Vec) -> UidIndexOp { - UidIndexOp::FlagDel(uuid, flags) + pub fn op_flag_del(&self, ident: MailIdent, flags: Vec) -> UidIndexOp { + UidIndexOp::FlagDel(ident, flags) } } @@ -80,60 +84,65 @@ impl BayouState for UidIndex { fn apply(&self, op: &UidIndexOp) -> Self { let mut new = self.clone(); match op { - UidIndexOp::MailAdd(uuid, uid, flags) => { + UidIndexOp::MailAdd(ident, uid, flags) => { + // Change UIDValidity if there is a conflict if *uid < new.internalseq { new.uidvalidity += new.internalseq - *uid; } + + // Assign the real uid let new_uid = new.internalseq; - if let Some(prev_uid) = new.mail_uid.get(uuid) { + if let Some(prev_uid) = new.mail_uid.get(ident) { new.mails_by_uid.remove(prev_uid); } else { - new.mail_flags.insert(*uuid, flags.clone()); + new.mail_flags.insert(*ident, flags.clone()); } - new.mails_by_uid.insert(new_uid, *uuid); - new.mail_uid.insert(*uuid, new_uid); + new.mails_by_uid.insert(new_uid, *ident); + new.mail_uid.insert(*ident, new_uid); new.internalseq += 1; new.uidnext = new.internalseq; } - UidIndexOp::MailDel(uuid) => { - if let Some(uid) = new.mail_uid.get(uuid) { + UidIndexOp::MailDel(ident) => { + if let Some(uid) = new.mail_uid.get(ident) { new.mails_by_uid.remove(uid); - new.mail_uid.remove(uuid); - new.mail_flags.remove(uuid); + new.mail_uid.remove(ident); + new.mail_flags.remove(ident); } new.internalseq += 1; } - UidIndexOp::FlagAdd(uuid, new_flags) => { + UidIndexOp::FlagAdd(ident, new_flags) => { // Upate mapping Email -> Flag - let mail_flags = new.mail_flags.entry(*uuid).or_insert(vec![]); + let mail_flags = new.mail_flags.entry(*ident).or_insert(vec![]); for flag in new_flags { if !mail_flags.contains(flag) { mail_flags.push(flag.to_string()); } } - // Update mapping Flag -> Email + // Update mapping Flag -> ImapUid + +/* let _ = new_flags.iter().map(|flag| { new.flags .entry(flag.clone()) - .or_insert(HashSet::new()) + .or_insert(OrdSet::new()) .update(*uuid) - }); + });*/ } - UidIndexOp::FlagDel(uuid, rm_flags) => { + UidIndexOp::FlagDel(ident, rm_flags) => { // Upate mapping Email -> Flag - if let Some(mail_flags) = new.mail_flags.get_mut(uuid) { + if let Some(mail_flags) = new.mail_flags.get_mut(ident) { mail_flags.retain(|x| !rm_flags.contains(x)); } - // Update mapping Flag -> Email - rm_flags.iter().for_each(|flag| { + // Update mapping Flag -> ImapUid + /*rm_flags.iter().for_each(|flag| { new.flags .entry(flag.clone()) .and_modify(|hs| { hs.remove(uuid); }); - }); + });*/ } } new @@ -144,7 +153,7 @@ impl BayouState for UidIndex { #[derive(Serialize, Deserialize)] struct UidIndexSerializedRepr { - mails: Vec<(ImapUid, MailUuid, Vec)>, + mails: Vec<(ImapUid, MailIdent, Vec)>, uidvalidity: ImapUidvalidity, uidnext: ImapUid, internalseq: ImapUid, @@ -202,7 +211,7 @@ impl Serialize for UidIndex { } } -impl<'de> Deserialize<'de> for MailUuid { +impl<'de> Deserialize<'de> for MailIdent { fn deserialize(d: D) -> Result where D: Deserializer<'de>, @@ -220,7 +229,7 @@ impl<'de> Deserialize<'de> for MailUuid { } } -impl Serialize for MailUuid { +impl Serialize for MailIdent { fn serialize(&self, serializer: S) -> Result where S: Serializer,