diff options
author | Manos Pitsidianakis <el13635@mail.ntua.gr> | 2019-05-14 21:47:47 +0300 |
---|---|---|
committer | Manos Pitsidianakis <el13635@mail.ntua.gr> | 2019-06-10 19:40:49 +0300 |
commit | 22d868f499bbf617a530fd67754c46a15896c4ec (patch) | |
tree | af124c4d4948f4de39a2f9114065cd53fcc6c985 | |
parent | 4582bcd5ae6a5ad7725a5a89f3e421de007d1525 (diff) |
save Account to disk
closes #114
-rw-r--r-- | melib/src/conf.rs | 2 | ||||
-rw-r--r-- | melib/src/error.rs | 2 | ||||
-rw-r--r-- | melib/src/mailbox.rs | 23 | ||||
-rw-r--r-- | melib/src/mailbox/collection.rs | 3 | ||||
-rw-r--r-- | melib/src/mailbox/email.rs | 9 | ||||
-rw-r--r-- | melib/src/mailbox/thread.rs | 389 | ||||
-rw-r--r-- | ui/src/components/mail.rs | 1 | ||||
-rw-r--r-- | ui/src/components/mail/compose.rs | 12 | ||||
-rw-r--r-- | ui/src/components/mail/listing/compact.rs | 24 | ||||
-rw-r--r-- | ui/src/components/mail/listing/thread.rs | 12 | ||||
-rw-r--r-- | ui/src/components/mail/view/thread.rs | 51 | ||||
-rw-r--r-- | ui/src/conf/accounts.rs | 13 | ||||
-rw-r--r-- | ui/src/conf/mailer.rs | 2 | ||||
-rw-r--r-- | ui/src/conf/pager.rs | 2 | ||||
-rw-r--r-- | ui/src/execute/actions.rs | 5 |
15 files changed, 315 insertions, 235 deletions
diff --git a/melib/src/conf.rs b/melib/src/conf.rs index 360cd730..02830d26 100644 --- a/melib/src/conf.rs +++ b/melib/src/conf.rs @@ -19,7 +19,7 @@ * along with meli. If not, see <http://www.gnu.org/licenses/>. */ -#[derive(Debug, Default, Clone)] +#[derive(Debug, Serialize, Default, Clone)] pub struct AccountSettings { pub name: String, pub root_folder: String, diff --git a/melib/src/error.rs b/melib/src/error.rs index 657dd38d..4e12428d 100644 --- a/melib/src/error.rs +++ b/melib/src/error.rs @@ -35,7 +35,7 @@ use nom; pub type Result<T> = result::Result<T, MeliError>; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Deserialize, Serialize)] pub struct MeliError { details: String, } diff --git a/melib/src/mailbox.rs b/melib/src/mailbox.rs index ac93cc30..c593bc8a 100644 --- a/melib/src/mailbox.rs +++ b/melib/src/mailbox.rs @@ -31,6 +31,8 @@ pub use self::email::*; pub mod backends; use self::backends::Folder; use crate::error::Result; +use crate::mailbox::thread::ThreadHash; + pub mod thread; pub use self::thread::{SortField, SortOrder, ThreadNode, Threads}; @@ -40,8 +42,9 @@ pub use self::collection::*; use std::option::Option; /// `Mailbox` represents a folder of mail. -#[derive(Debug, Clone, Default)] +#[derive(Debug, Deserialize, Serialize, Clone, Default)] pub struct Mailbox { + #[serde(skip_serializing, skip_deserializing)] pub folder: Folder, name: String, pub collection: Collection, @@ -72,28 +75,28 @@ impl Mailbox { pub fn len(&self) -> usize { self.collection.len() } - pub fn thread_to_mail_mut(&mut self, i: usize) -> &mut Envelope { + pub fn thread_to_mail_mut(&mut self, h: ThreadHash) -> &mut Envelope { self.collection .envelopes - .entry(self.collection.threads.thread_to_mail(i)) + .entry(self.collection.threads.thread_to_mail(h)) .or_default() } - pub fn thread_to_mail(&self, i: usize) -> &Envelope { - &self.collection.envelopes[&self.collection.threads.thread_to_mail(i)] + pub fn thread_to_mail(&self, h: ThreadHash) -> &Envelope { + &self.collection.envelopes[&self.collection.threads.thread_to_mail(h)] } - pub fn threaded_mail(&self, i: usize) -> EnvelopeHash { - self.collection.threads.thread_to_mail(i) + pub fn threaded_mail(&self, h: ThreadHash) -> EnvelopeHash { + self.collection.threads.thread_to_mail(h) } pub fn mail_and_thread(&mut self, i: EnvelopeHash) -> (&mut Envelope, &ThreadNode) { let thread; { let x = &mut self.collection.envelopes.entry(i).or_default(); - thread = &self.collection.threads[x.thread()]; + thread = &self.collection.threads[&x.thread()]; } (self.collection.envelopes.entry(i).or_default(), thread) } - pub fn thread(&self, i: usize) -> &ThreadNode { - &self.collection.threads.thread_nodes()[i] + pub fn thread(&self, h: ThreadHash) -> &ThreadNode { + &self.collection.threads.thread_nodes()[&h] } pub fn insert_sent_folder(&mut self, _sent: &Mailbox) { diff --git a/melib/src/mailbox/collection.rs b/melib/src/mailbox/collection.rs index 4dd3ebc0..b53987ea 100644 --- a/melib/src/mailbox/collection.rs +++ b/melib/src/mailbox/collection.rs @@ -7,8 +7,9 @@ use std::ops::{Deref, DerefMut}; use fnv::FnvHashMap; /// `Mailbox` represents a folder of mail. -#[derive(Debug, Clone, Default)] +#[derive(Debug, Clone, Deserialize, Default, Serialize)] pub struct Collection { + #[serde(skip_serializing, skip_deserializing)] folder: Folder, pub envelopes: FnvHashMap<EnvelopeHash, Envelope>, date_index: BTreeMap<UnixTimestamp, EnvelopeHash>, diff --git a/melib/src/mailbox/email.rs b/melib/src/mailbox/email.rs index ee42ae50..30306e8c 100644 --- a/melib/src/mailbox/email.rs +++ b/melib/src/mailbox/email.rs @@ -34,6 +34,7 @@ use parser::BytesExt; use super::backends::BackendOp; use crate::error::{MeliError, Result}; +use crate::mailbox::thread::ThreadHash; use std::borrow::Cow; use std::cmp::Ordering; @@ -320,7 +321,7 @@ pub struct Envelope { references: Option<References>, timestamp: UnixTimestamp, - thread: usize, + thread: ThreadHash, hash: EnvelopeHash, @@ -355,7 +356,7 @@ impl Envelope { timestamp: 0, - thread: 0, + thread: ThreadHash::null(), hash, flags: Flag::default(), @@ -731,10 +732,10 @@ impl Envelope { None => Vec::new(), } } - pub fn thread(&self) -> usize { + pub fn thread(&self) -> ThreadHash { self.thread } - pub fn set_thread(&mut self, new_val: usize) { + pub fn set_thread(&mut self, new_val: ThreadHash) { self.thread = new_val; } pub fn set_datetime(&mut self, new_val: chrono::DateTime<chrono::FixedOffset>) { diff --git a/melib/src/mailbox/thread.rs b/melib/src/mailbox/thread.rs index ac12fb60..a4e1c47f 100644 --- a/melib/src/mailbox/thread.rs +++ b/melib/src/mailbox/thread.rs @@ -34,6 +34,7 @@ use crate::mailbox::email::parser::BytesExt; use crate::mailbox::email::*; +use uuid::Uuid; use fnv::{FnvHashMap, FnvHashSet}; use std::cell::{Ref, RefCell}; @@ -48,46 +49,71 @@ use std::str::FromStr; type Envelopes = FnvHashMap<EnvelopeHash, Envelope>; +#[derive(PartialEq, Hash, Eq, Debug, Copy, Clone, Serialize, Deserialize, Default)] +pub struct ThreadHash(Uuid); + +impl ThreadHash { + fn new() -> Self { + ThreadHash(Uuid::new_v4()) + } + pub fn null() -> Self { + ThreadHash(Uuid::nil()) + } +} + /* Helper macros to avoid repeating ourselves */ -fn rec_change_root_parent(b: &mut Vec<ThreadNode>, idx: usize, new_root: usize) { - b[idx].thread_group = new_root; - if let Some(p) = b[idx].parent { +fn rec_change_root_parent( + b: &mut FnvHashMap<ThreadHash, ThreadNode>, + idx: ThreadHash, + new_root: ThreadHash, +) { + let entry = b.entry(idx).or_default(); + entry.thread_group = new_root; + if let Some(p) = entry.parent { rec_change_children(b, p, new_root); rec_change_root_parent(b, p, new_root); } } -fn rec_change_children(b: &mut Vec<ThreadNode>, idx: usize, new_root: usize) { - b[idx].thread_group = new_root; +fn rec_change_children( + b: &mut FnvHashMap<ThreadHash, ThreadNode>, + idx: ThreadHash, + new_root: ThreadHash, +) { + let entry = b.entry(idx).or_default(); + entry.thread_group = new_root; - for c in b[idx].children.clone() { + for c in entry.children.clone() { rec_change_children(b, c, new_root); } } macro_rules! remove_from_parent { - ($buf:expr, $idx:expr) => { - if let Some(p) = $buf[$idx].parent { - if let Some(pos) = $buf[p].children.iter().position(|c| *c == $idx) { - $buf[p].children.remove(pos); + ($buf:expr, $idx:expr) => {{ + let entry = $buf.entry($idx).or_default(); + if let Some(p) = entry.parent { + if let Some(pos) = $buf[&p].children.iter().position(|c| *c == $idx) { + $buf.entry(p).and_modify(|e| { + e.children.remove(pos); + }); } rec_change_root_parent($buf, p, p); } - $buf[$idx].parent = None; + $buf.entry($idx).and_modify(|e| e.parent = None); rec_change_children($buf, $idx, $idx); - $buf[$idx].thread_group = $idx; - }; + $buf.entry($idx).and_modify(|e| e.thread_group = $idx); + }}; } macro_rules! make { (($p:expr)parent of($c:expr), $buf:expr) => { remove_from_parent!($buf, $c); - if !($buf[$p]).children.contains(&$c) { - $buf[$p].children.push($c); + if !($buf[&$p]).children.contains(&$c) { + $buf.entry($p).and_modify(|e| e.children.push($c)); } else { panic!(); } - $buf[$c].parent = Some($p); + $buf.entry($c).and_modify(|e| e.parent = Some($p)); union($buf, $c, $p); }; } @@ -201,7 +227,7 @@ impl FromStr for SortOrder { #[derive(Clone, Deserialize, Serialize)] struct ThreadTree { - id: usize, + id: ThreadHash, children: Vec<ThreadTree>, } @@ -212,7 +238,7 @@ impl fmt::Debug for ThreadTree { } impl ThreadTree { - fn new(id: usize) -> Self { + fn new(id: ThreadHash) -> Self { ThreadTree { id, children: Vec::new(), @@ -241,8 +267,8 @@ pub struct ThreadsIterator<'a> { tree: Ref<'a, Vec<ThreadTree>>, } impl<'a> Iterator for ThreadsIterator<'a> { - type Item = (usize, usize, bool); - fn next(&mut self) -> Option<(usize, usize, bool)> { + type Item = (usize, ThreadHash, bool); + fn next(&mut self) -> Option<(usize, ThreadHash, bool)> { { let mut tree = &(*self.tree); for i in &self.stack { @@ -293,8 +319,8 @@ pub struct ThreadIterator<'a> { tree: Ref<'a, Vec<ThreadTree>>, } impl<'a> Iterator for ThreadIterator<'a> { - type Item = (usize, usize); - fn next(&mut self) -> Option<(usize, usize)> { + type Item = (usize, ThreadHash); + fn next(&mut self) -> Option<(usize, ThreadHash)> { { let mut tree = &(*self.tree); for i in &self.stack { @@ -324,8 +350,8 @@ impl<'a> Iterator for ThreadIterator<'a> { #[derive(Clone, Debug, Deserialize, Serialize)] pub struct ThreadNode { message: Option<EnvelopeHash>, - parent: Option<usize>, - children: Vec<usize>, + parent: Option<ThreadHash>, + children: Vec<ThreadHash>, date: UnixTimestamp, indentation: usize, show_subject: bool, @@ -334,7 +360,7 @@ pub struct ThreadNode { has_unseen: bool, /* Union/Find set fields */ - thread_group: usize, + thread_group: ThreadHash, rank: i32, } @@ -350,13 +376,19 @@ impl Default for ThreadNode { len: 0, has_unseen: false, - thread_group: 0, + thread_group: ThreadHash::default(), rank: 0, } } } impl ThreadNode { + fn new(thread_group: ThreadHash) -> Self { + ThreadNode { + thread_group, + ..Default::default() + } + } pub fn show_subject(&self) -> bool { self.show_subject } @@ -381,7 +413,7 @@ impl ThreadNode { self.message.is_some() } - pub fn parent(&self) -> Option<usize> { + pub fn parent(&self) -> Option<ThreadHash> { self.parent } @@ -389,7 +421,7 @@ impl ThreadNode { self.parent.is_some() } - pub fn children(&self) -> &[usize] { + pub fn children(&self) -> &[ThreadHash] { &self.children } @@ -400,11 +432,11 @@ impl ThreadNode { #[derive(Clone, Debug, Default, Deserialize, Serialize)] pub struct Threads { - thread_nodes: Vec<ThreadNode>, - root_set: RefCell<Vec<usize>>, + thread_nodes: FnvHashMap<ThreadHash, ThreadNode>, + root_set: RefCell<Vec<ThreadHash>>, tree: RefCell<Vec<ThreadTree>>, - message_ids: FnvHashMap<Vec<u8>, usize>, + message_ids: FnvHashMap<Vec<u8>, ThreadHash>, pub hash_set: FnvHashSet<EnvelopeHash>, sort: RefCell<(SortField, SortOrder)>, subsort: RefCell<(SortField, SortOrder)>, @@ -425,8 +457,8 @@ pub struct RootIterator<'a> { } impl<'a> Iterator for RootIterator<'a> { - type Item = usize; - fn next(&mut self) -> Option<usize> { + type Item = ThreadHash; + fn next(&mut self) -> Option<ThreadHash> { { if self.pos == self.root_tree.len() { return None; @@ -436,15 +468,16 @@ impl<'a> Iterator for RootIterator<'a> { } } } -fn find(buf: &mut Vec<ThreadNode>, i: usize) -> usize { - if buf[i].thread_group == i { - return i; +fn find(buf: &mut FnvHashMap<ThreadHash, ThreadNode>, h: ThreadHash) -> ThreadHash { + if buf[&h].thread_group == h { + return h; } - let p = buf[i].thread_group; - buf[i].thread_group = find(buf, p); - buf[i].thread_group + let p = buf[&h].thread_group; + let new_group = find(buf, p); + buf.entry(h).and_modify(|e| e.thread_group = new_group); + new_group } -fn union(buf: &mut Vec<ThreadNode>, x: usize, y: usize) -> usize { +fn union(buf: &mut FnvHashMap<ThreadHash, ThreadNode>, x: ThreadHash, y: ThreadHash) -> ThreadHash { let mut x_root = find(buf, x); let mut y_root = find(buf, y); @@ -453,24 +486,26 @@ fn union(buf: &mut Vec<ThreadNode>, x: usize, y: usize) -> usize { return x_root; } - if buf[x_root].rank < buf[y_root].rank { + if buf[&x_root].rank < buf[&y_root].rank { mem::swap(&mut x_root, &mut y_root); } // x and y are not in same set, so we merge them // - buf[y_root].thread_group = x_root; - if buf[x_root].rank == buf[y_root].rank { - buf[x_root].rank += 1; + buf.entry(y_root).and_modify(|e| e.thread_group = x_root); + if buf[&x_root].rank == buf[&y_root].rank { + buf.entry(x_root).and_modify(|e| { + e.rank += 1; + }); } x_root } impl Threads { - fn find(&mut self, i: usize) -> usize { + fn find(&mut self, i: ThreadHash) -> ThreadHash { find(&mut self.thread_nodes, i) } - fn union(&mut self, x: usize, y: usize) -> usize { + fn union(&mut self, x: ThreadHash, y: ThreadHash) -> ThreadHash { let mut x_root = self.find(x); let mut y_root = self.find(y); @@ -479,47 +514,51 @@ impl Threads { return x_root; } - if self.thread_nodes[x_root].rank < self.thread_nodes[y_root].rank { + if self.thread_nodes[&x_root].rank < self.thread_nodes[&y_root].rank { mem::swap(&mut x_root, &mut y_root); } // x and y are not in same set, so we merge them // - self.thread_nodes[y_root].thread_group = x_root; - if self.thread_nodes[x_root].rank == self.thread_nodes[y_root].rank { - self.thread_nodes[x_root].rank += 1; + self.thread_nodes + .entry(y_root) + .and_modify(|e| e.thread_group = x_root); + if self.thread_nodes[&x_root].rank == self.thread_nodes[&y_root].rank { + self.thread_nodes.entry(x_root).and_modify(|e| e.rank += 1); } x_root } - fn prune_empty_nodes(&mut self, root_set: &mut Vec<usize>) { + fn prune_empty_nodes(&mut self, root_set: &mut Vec<ThreadHash>) { fn prune( - thread_nodes: &mut Vec<ThreadNode>, - idx: usize, - root_set: &mut Vec<usize>, + thread_nodes: &mut FnvHashMap<ThreadHash, ThreadNode>, + idx: ThreadHash, + root_set: &mut Vec<ThreadHash>, ) -> bool { /* "If it is an empty container with no children, nuke it." */ - if !thread_nodes[idx].has_message() && thread_nodes[idx].children.is_empty() { + if !thread_nodes[&idx].has_message() && thread_nodes[&idx].children.is_empty() { remove_from_parent!(thread_nodes, idx); return true; } - if !thread_nodes[idx].has_message() && !thread_nodes[idx].has_parent() { - if thread_nodes[idx].children.len() == 1 { + if !thread_nodes[&idx].has_message() && !thread_nodes[&idx].has_parent() { + if thread_nodes[&idx].children.len() == 1 { /* "Do not promote the children if doing so would promote them to the root set * -- unless there is only one child, in which case, do." */ - let child = thread_nodes[idx].children[0]; + let child = thread_nodes[&idx].children[0]; root_set.push(child); remove_from_parent!(thread_nodes, child); return true; // Pruned } - } else if let Some(p) = thread_nodes[idx].parent { - if !thread_nodes[idx].has_message() { - let orphans = thread_nodes[idx].children.clone(); + } else if let Some(p) = thread_nodes[&idx].parent { + if !thread_nodes[&idx].has_message() { + let orphans = thread_nodes[&idx].children.clone(); for c in orphans { make!((p) parent of (c), thread_nodes); } remove_from_parent!(thread_nodes, idx); - thread_nodes[idx].children.clear(); + thread_nodes.entry(idx).and_modify(|e| { + e.children.clear(); + }); return true; // Pruned } } @@ -528,15 +567,15 @@ impl Threads { */ let mut c_idx = 0; loop { - if c_idx == thread_nodes[idx].children.len() { + if c_idx == thread_nodes[&idx].children.len() { break; } - let c = thread_nodes[idx].children[c_idx]; + let c = thread_nodes[&idx].children[c_idx]; if !prune(thread_nodes, c, root_set) { c_idx += 1; } } - !thread_nodes[idx].has_message() && thread_nodes[idx].children.is_empty() + !thread_nodes[&idx].has_message() && thread_nodes[&idx].children.is_empty() } let mut idx = 0; @@ -556,10 +595,12 @@ impl Threads { /* To reconstruct thread information from the mails we need: */ /* a vector to hold thread members */ - let thread_nodes: Vec<ThreadNode> = - Vec::with_capacity((collection.len() as f64 * 1.2) as usize); + let thread_nodes: FnvHashMap<ThreadHash, ThreadNode> = FnvHashMap::with_capacity_and_hasher( + (collection.len() as f64 * 1.2) as usize, + Default::default(), + ); /* A hash table of Message IDs */ - let message_ids: FnvHashMap<Vec<u8>, usize> = + let message_ids: FnvHashMap<Vec<u8>, ThreadHash> = FnvHashMap::with_capacity_and_hasher(collection.len(), Default::default()); let hash_set: FnvHashSet<EnvelopeHash> = FnvHashSet::with_capacity_and_hasher(collection.len(), Default::default()); @@ -616,11 +657,11 @@ impl Threads { fn create_root_set(&mut self, collection: &Envelopes) { /* Walk over the elements of message_ids, and gather a list of the ThreadNode objects that * have no parents. These are the root messages of each thread */ - let mut root_set: Vec<usize> = Vec::with_capacity(collection.len()); + let mut root_set: Vec<ThreadHash> = Vec::with_capacity(collection.len()); /* Find the root set */ for v in self.message_ids.values() { - if self.thread_nodes[*v].parent.is_none() { + if self.thread_nodes[v].parent.is_none() { root_set.push(*v); } } @@ -635,22 +676,22 @@ impl Threads { * messages which don't have References headers at all still get threaded (to the extent * possible, at least.)" */ - let mut subject_table: FnvHashMap<Vec<u8>, (bool, usize)> = + let mut subject_table: FnvHashMap<Vec<u8>, (bool, ThreadHash)> = FnvHashMap::with_capacity_and_hasher(collection.len(), Default::default()); for &r in root_set.iter() { /* "Find the subject of that sub-tree": */ - let (mut subject, mut is_re): (_, bool) = if self.thread_nodes[r].message.is_some() { + let (mut subject, mut is_re): (_, bool) = if self.thread_nodes[&r].message.is_some() { /* "If there is a message in the Container, the subject is the subject of that * message. " */ - let msg_idx = self.thread_nodes[r].message.unwrap(); + let msg_idx = self.thread_nodes[&r].message.unwrap(); let envelope = &collection[&msg_idx]; (envelope.subject(), !envelope.references().is_empty()) } else { /* "If there is no message in the Container, then the Container will have at least * one child Container, and that Container will have a message. Use the subject of * that message instead." */ - let msg_idx = self.thread_nodes[self.thread_nodes[r].children[0]] + let msg_idx = self.thread_nodes[&self.thread_nodes[&r].children[0]] .message .unwrap(); let envelope = &collection[&msg_idx]; @@ -677,7 +718,7 @@ impl Threads { * "The container in the table has a ``Re:'' version of this subject, and this * container has a non-``Re:'' version of this subject. The non-re version is the * more interesting of the two." */ - if (!self.thread_nodes[id].has_message() && self.thread_nodes[r].has_message()) + if (!self.thread_nodes[&id].has_message() && self.thread_nodes[&r].has_message()) || (other_is_re && !is_re) { mem::replace( @@ -697,12 +738,12 @@ impl Threads { let r = root_set[i]; /* "Find the subject of this Container (as above.)" */ - let (mut subject, mut is_re): (_, bool) = if self.thread_nodes[r].message.is_some() { - let msg_idx = self.thread_nodes[r].message.unwrap(); + let (mut subject, mut is_re): (_, bool) = if self.thread_nodes[&r].message.is_some() { + let msg_idx = self.thread_nodes[&r].message.unwrap(); let envelope = &collection[&msg_idx]; (envelope.subject(), !envelope.references().is_empty()) } else { - let msg_idx = self.thread_nodes[self.thread_nodes[r].children[0]] + let msg_idx = self.thread_nodes[&self.thread_nodes[&r].children[0]] .message .unwrap(); let envelope = &collection[&msg_idx]; @@ -718,7 +759,7 @@ impl Threads { let (other_is_re, other_idx) = subject_table[subject]; /* "If it is null, or if it is this container, continue." */ - if !self.thread_nodes[other_idx].has_message() || other_idx == r { + if !self.thread_nodes[&other_idx].has_message() || other_idx == r { continue; } @@ -729,8 +770,9 @@ impl Threads { * "If both are dummies, append one's children to the other, and remove the now-empty * container." */ - if !self.thread_nodes[r].has_message() && !self.thread_nodes[other_idx].has_message() { - let children = self.thread_nodes[r].children.clone(); + if !self.thread_nodes[&r].has_message() && !self.thread_nodes[&other_idx].has_message() + { + let children = self.thread_nodes[&r].children.clone(); for c in children { make!((other_idx) parent of (c), &mut self.thread_nodes); } @@ -740,16 +782,16 @@ impl Threads { * of the empty, and a sibling of the other ``real'' messages with the same subject * (the empty's children.)" */ - } else if self.thread_nodes[r].has_message() - && !self.thread_nodes[other_idx].has_message() + } else if self.thread_nodes[&r].has_message() + && !self.thread_nodes[&other_idx].has_message() { make!((other_idx) parent of (r), &mut self.thread_nodes); if !root_set.contains(&other_idx) { root_set.push(other_idx); } roots_to_remove.push(i); - } else if !self.thread_nodes[r].has_message() - && self.thread_nodes[other_idx].has_message() + } else if !self.thread_nodes[&r].has_message() + && self.thread_nodes[&other_idx].has_message() { make!((r) parent of (other_idx), &mut self.thread_nodes); if let Some(pos) = root_set.iter().position(|&i| i == other_idx) { @@ -759,7 +801,7 @@ impl Threads { * "If that container is a non-empty, and that message's subject does not begin with ``Re:'', but this * message's subject does, then make this be a child of the other." */ - } else if self.thread_nodes[other_idx].has_message() && !other_is_re && is_re { + } else if self.thread_nodes[&other_idx].has_message() && !other_is_re && is_re { make!((other_idx) parent of (r), &mut self.thread_nodes); roots_to_remove.push(i); @@ -769,7 +811,7 @@ impl Threads { * without will be in the hash table, regardless of the order in which they were * seen.)" */ - } else if self.thread_nodes[other_idx].has_message() && other_is_re && !is_re { + } else if self.thread_nodes[&other_idx].has_message() && other_is_re && !is_re { make!((r) parent of (other_idx), &mut self.thread_nodes); if let Some(pos) = root_set.iter().position(|r| *r == other_idx) { roots_to_remove.push(pos); @@ -780,9 +822,8 @@ impl Threads { * hierarchical relationship which might not be true." */ } else { - self.thread_nodes.push(Default::default()); - let new_id = self.thread_nodes.len() - 1; - self.thread_nodes[new_id].thread_group = new_id; + let new_id = ThreadHash::new(); + self.thread_nodes.insert(new_id, ThreadNode::new(new_id)); make!((new_id) parent of (r), &mut self.thread_nodes); make!((new_id) parent of (other_idx), &mut self.thread_nodes); root_set[i] = new_id; @@ -827,20 +868,19 @@ impl Threads { * - hash_set * - message fields in thread_nodes */ - let idx = if let Some((idx, node)) = self + let thread_hash = if let Some((key, node)) = self .thread_nodes .iter_mut() - .enumerate() .find(|(_, n)| n.message.map(|n| n == old_hash).unwrap_or(false)) { node.message = Some(new_hash); - idx + *key } else { return Err(()); }; self.hash_set.remove(&old_hash); self.hash_set.insert(new_hash); - self.rebuild_thread(idx, collection); + self.rebuild_thread(thread_hash, collection); Ok(()) } @@ -856,15 +896,15 @@ impl Threads { // debug!("DEBUG: {} in threads is idx= {}", envelope_hash, pos); //} - let t_id: usize; + let t_id: ThreadHash; { - if let Some(pos) = self + if let Some((pos, n)) = self .thread_nodes - .iter() - .position(|n| n.message.map(|n| n == envelope_hash).unwrap_or(false)) + .iter_mut() + .find(|(_, n)| n.message.map(|n| n == envelope_hash).unwrap_or(false)) { - t_id = pos; - self.thread_nodes[pos].message = None; + t_id = *pos; + n.message = None; } else { /* else it was deleted during a thread_rebuild or others */ return; @@ -874,7 +914,7 @@ impl Threads { let mut node_idx = t_id; /* Trace path back to root ThreadNode */ - while let Some(p) = &self.thread_nodes[node_idx].parent { + while let Some(p) = &self.thread_nodes[&node_idx].parent { node_idx = *p; } { @@ -895,7 +935,7 @@ impl Threads { } } - let mut root_set: Vec<usize> = self.tree.borrow().iter().map(|t| t.id).collect(); + let mut root_set: Vec<ThreadHash> = self.tree.borrow().iter().map(|t| t.id).collect(); self.prune_empty_nodes(&mut root_set); self.tree.borrow_mut().retain(|t| root_set.contains(&t.id)); } @@ -922,7 +962,7 @@ impl Threads { } self.create_root_set(collection); - let mut root_set: Vec<usize> = self.tree.borrow().iter().map(|t| t.id).collect(); + let mut root_set: Vec<ThreadHash> = self.tree.borrow().iter().map(|t| t.id).collect(); self.prune_empty_nodes(&mut root_set); let tree = self.tree.get_mut(); tree.retain(|t| root_set.contains(&t.id)); @@ -966,11 +1006,11 @@ impl Threads { } /* Update thread tree information on envelope insertion */ - fn rebuild_thread(&mut self, id: usize, collection: &Envelopes) { + fn rebuild_thread(&mut self, id: ThreadHash, collection: &Envelopes) { let mut node_idx = id; let mut stack = Vec::with_capacity(32); - let no_parent: bool = if let Some(node) = self.thread_nodes.get(node_idx) { + let no_parent: bool = if let Some(node) = self.thread_nodes.get(&node_idx) { node.parent.is_none() } else { false @@ -987,7 +1027,7 @@ impl Threads { } /* Trace path back to root ThreadNode */ - while let Some(p) = &self.thread_nodes[node_idx].parent { + while let Some(p) = &self.thread_nodes[&node_idx].parent { node_idx = *p; stack.push(node_idx); } @@ -1053,18 +1093,18 @@ impl Threads { for t in tree.iter_mut() { t.children.sort_by(|a, b| match subsort { (SortField::Date, SortOrder::Desc) => { - let a = &self.thread_nodes[a.id]; - let b = &self.thread_nodes[b.id]; + let a = &self.thread_nodes[&a.id]; + let b = &self.thread_nodes[&b.id]; b.date.cmp(&a.date) } (SortField::Date, SortOrder::Asc) => { - let a = &self.thread_nodes[a.id]; - let b = &self.thread_nodes[b.id]; + let a = &self.thread_nodes[&a.id]; + let b = &self.thread_nodes[&b.id]; a.date.cmp(&b.date) } (SortField::Subject, SortOrder::Desc) => { - let a = &self.thread_nodes[a.id].message(); - let b = &self.thread_nodes[b.id].message(); + let a = &self.thread_nodes[&a.id].message(); + let b = &self.thread_nodes[&b.id].message(); if a.is_none() || b.is_none() { return Ordering::Equal; @@ -1074,8 +1114,8 @@ impl Threads { ma.subject().cmp(&mb.subject()) } (SortField::Subject, SortOrder::Asc) => { - let a = &self.thread_nodes[a.id].message(); - let b = &self.thread_nodes[b.id].message(); + let a = &self.thread_nodes[&a.id].message(); + let b = &self.thread_nodes[&b.id].message(); if a.is_none() || b.is_none() { return Ordering::Equal; @@ -1092,18 +1132,18 @@ impl Threads { let tree = &mut self.tree.borrow_mut(); tree.sort_by(|a, b| match sort { (SortField::Date, SortOrder::Desc) => { - let a = &self.thread_nodes[a.id]; - let b = &self.thread_nodes[b.id]; + let a = &self.thread_nodes[&a.id]; + let b = &self.thread_nodes[&b.id]; b.date.cmp(&a.date) } (SortField::Date, SortOrder::Asc) => { - let a = &self.thread_nodes[a.id]; - let b = &self.thread_nodes[b.id]; + let a = &self.thread_nodes[&a.id]; + let b = &self.thread_nodes[&b.id]; a.date.cmp(&b.date) } (SortField::Subject, SortOrder::Desc) => { - let a = &self.thread_nodes[a.id].message(); - let b = &self.thread_nodes[b.id].message(); + let a = &self.thread_nodes[&a.id].message(); + let b = &self.thread_nodes[&b.id].message(); if a.is_none() || b.is_none() { return Ordering::Equal; @@ -1113,8 |