From 78eecbb104c40baf1e3ffc5a18abf29baa8541bb Mon Sep 17 00:00:00 2001 From: Manos Pitsidianakis Date: Sat, 2 Nov 2019 12:14:31 +0200 Subject: [PATCH] melib: Hide Envelope behind RwLock Envelope can now only be accessed from within a RwLock. Two new structs are introduced: EnvelopeRef and EnvelopeRefMut. These hold a reference to an Envelope and the mutex guard that keeps them alive. This change allows sharing of the envelopes hash map amongst threads. --- melib/Cargo.toml | 2 +- melib/src/collection.rs | 104 +++++++++++----- melib/src/thread.rs | 116 +++++++++++------- ui/src/cache.rs | 2 + ui/src/components/mail/compose.rs | 22 ++-- ui/src/components/mail/listing.rs | 8 +- ui/src/components/mail/listing/compact.rs | 44 ++++--- .../components/mail/listing/conversations.rs | 34 ++--- ui/src/components/mail/listing/plain.rs | 33 ++--- ui/src/components/mail/listing/thread.rs | 23 ++-- ui/src/components/mail/view.rs | 24 ++-- ui/src/components/mail/view/thread.rs | 24 ++-- ui/src/components/utilities.rs | 3 +- ui/src/conf/accounts.rs | 60 ++++----- ui/src/sqlite3.rs | 22 ++-- 15 files changed, 305 insertions(+), 216 deletions(-) diff --git a/melib/Cargo.toml b/melib/Cargo.toml index edd951cae..1451db4aa 100644 --- a/melib/Cargo.toml +++ b/melib/Cargo.toml @@ -19,7 +19,7 @@ notify-rust = { version = "^3", optional = true } termion = "1.5.1" xdg = "2.1.0" native-tls = { version ="0.2", optional=true } -serde = "1.0.71" +serde = { version = "1.0.71", features = ["rc", ] } serde_derive = "1.0.71" bincode = "1.2.0" uuid = { version = "0.7.4", features = ["serde", "v4"] } diff --git a/melib/src/collection.rs b/melib/src/collection.rs index e850f7edd..b5e79d732 100644 --- a/melib/src/collection.rs +++ b/melib/src/collection.rs @@ -4,12 +4,45 @@ use std::collections::BTreeMap; use std::fs; use std::io; use std::ops::{Deref, DerefMut}; +use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard}; use fnv::FnvHashMap; +pub struct EnvelopeRef<'g> { + guard: RwLockReadGuard<'g, FnvHashMap>, + env_hash: EnvelopeHash, +} + +impl Deref for EnvelopeRef<'_> { + type Target = Envelope; + + fn deref(&self) -> &Envelope { + self.guard.get(&self.env_hash).unwrap() + } +} + +pub struct EnvelopeRefMut<'g> { + guard: RwLockWriteGuard<'g, FnvHashMap>, + env_hash: EnvelopeHash, +} + +impl Deref for EnvelopeRefMut<'_> { + type Target = Envelope; + + fn deref(&self) -> &Envelope { + self.guard.get(&self.env_hash).unwrap() + } +} + +impl DerefMut for EnvelopeRefMut<'_> { + fn deref_mut(&mut self) -> &mut Envelope { + self.guard.get_mut(&self.env_hash).unwrap() + } +} + #[derive(Debug, Clone, Deserialize, Default, Serialize)] pub struct Collection { - pub envelopes: FnvHashMap, + pub envelopes: Arc>>, message_ids: FnvHashMap, EnvelopeHash>, date_index: BTreeMap, subject_index: Option>, @@ -48,7 +81,7 @@ impl Collection { let threads = FnvHashMap::with_capacity_and_hasher(16, Default::default()); Collection { - envelopes, + envelopes: Arc::new(RwLock::new(envelopes)), date_index, message_ids, subject_index, @@ -58,16 +91,16 @@ impl Collection { } pub fn len(&self) -> usize { - self.envelopes.len() + self.envelopes.read().unwrap().len() } pub fn is_empty(&self) -> bool { - self.envelopes.is_empty() + self.envelopes.read().unwrap().is_empty() } pub fn remove(&mut self, envelope_hash: EnvelopeHash, folder_hash: FolderHash) { debug!("DEBUG: Removing {}", envelope_hash); - self.envelopes.remove(&envelope_hash); + self.envelopes.write().unwrap().remove(&envelope_hash); self.threads .entry(folder_hash) .or_default() @@ -86,14 +119,14 @@ impl Collection { new_hash: EnvelopeHash, folder_hash: FolderHash, ) { - if !self.envelopes.contains_key(&old_hash) { + if !self.envelopes.write().unwrap().contains_key(&old_hash) { return; } - let mut env = self.envelopes.remove(&old_hash).unwrap(); + let mut env = self.envelopes.write().unwrap().remove(&old_hash).unwrap(); env.set_hash(new_hash); self.message_ids .insert(env.message_id().raw().to_vec(), new_hash); - self.envelopes.insert(new_hash, env); + self.envelopes.write().unwrap().insert(new_hash, env); { if self .threads @@ -150,9 +183,9 @@ impl Collection { } = self; if !threads.contains_key(&folder_hash) { - threads.insert(folder_hash, Threads::new(&mut new_envelopes)); + threads.insert(folder_hash, Threads::new(new_envelopes.len())); for (h, e) in new_envelopes { - envelopes.insert(h, e); + envelopes.write().unwrap().insert(h, e); } } else { threads.entry(folder_hash).and_modify(|t| { @@ -165,7 +198,10 @@ impl Collection { .unwrap() }); for h in ordered_hash_set { - envelopes.insert(h, new_envelopes.remove(&h).unwrap()); + envelopes + .write() + .unwrap() + .insert(h, new_envelopes.remove(&h).unwrap()); t.insert(envelopes, h); } }); @@ -178,17 +214,19 @@ impl Collection { continue; } if sent_folder.map(|f| f == folder_hash).unwrap_or(false) { + let envelopes_lck = envelopes.read().unwrap(); let mut ordered_hash_set = threads[&folder_hash] .hash_set .iter() .cloned() .collect::>(); ordered_hash_set.sort_by(|a, b| { - envelopes[a] + envelopes_lck[a] .date() - .partial_cmp(&envelopes[b].date()) + .partial_cmp(&envelopes_lck[b].date()) .unwrap() }); + drop(envelopes_lck); let mut updated = false; for h in ordered_hash_set { updated |= threads.entry(t_fh).or_default().insert_reply(envelopes, h); @@ -199,17 +237,19 @@ impl Collection { continue; } if sent_folder.map(|f| f == t_fh).unwrap_or(false) { + let envelopes_lck = envelopes.read().unwrap(); let mut ordered_hash_set = threads[&t_fh] .hash_set .iter() .cloned() .collect::>(); ordered_hash_set.sort_by(|a, b| { - envelopes[a] + envelopes_lck[a] .date() - .partial_cmp(&envelopes[b].date()) + .partial_cmp(&envelopes_lck[b].date()) .unwrap() }); + drop(envelopes_lck); let mut updated = false; for h in ordered_hash_set { updated |= threads @@ -235,12 +275,12 @@ impl Collection { mut envelope: Envelope, folder_hash: FolderHash, ) { - let old_env = self.envelopes.remove(&old_hash).unwrap(); + let old_env = self.envelopes.write().unwrap().remove(&old_hash).unwrap(); envelope.set_thread(old_env.thread()); let new_hash = envelope.hash(); self.message_ids .insert(envelope.message_id().raw().to_vec(), new_hash); - self.envelopes.insert(new_hash, envelope); + self.envelopes.write().unwrap().insert(new_hash, envelope); if self.sent_folder.map(|f| f == folder_hash).unwrap_or(false) { for (_, t) in self.threads.iter_mut() { t.update_envelope(&self.envelopes, old_hash, new_hash) @@ -273,11 +313,11 @@ impl Collection { } } - pub fn insert(&mut self, envelope: Envelope, folder_hash: FolderHash) -> &Envelope { + pub fn insert(&mut self, envelope: Envelope, folder_hash: FolderHash) { let hash = envelope.hash(); self.message_ids .insert(envelope.message_id().raw().to_vec(), hash); - self.envelopes.insert(hash, envelope); + self.envelopes.write().unwrap().insert(hash, envelope); if !self .threads .entry(folder_hash) @@ -289,26 +329,26 @@ impl Collection { .or_default() .insert(&mut self.envelopes, hash); } - &self.envelopes[&hash] } + pub fn insert_reply(&mut self, env_hash: EnvelopeHash) { - debug_assert!(self.envelopes.contains_key(&env_hash)); + debug_assert!(self.envelopes.read().unwrap().contains_key(&env_hash)); for (_, t) in self.threads.iter_mut() { t.insert_reply(&mut self.envelopes, env_hash); } } -} -impl Deref for Collection { - type Target = FnvHashMap; + pub fn get_env<'g>(&'g self, env_hash: EnvelopeHash) -> EnvelopeRef<'g> { + let guard: RwLockReadGuard<'g, _> = self.envelopes.read().unwrap(); + EnvelopeRef { guard, env_hash } + } - fn deref(&self) -> &FnvHashMap { - &self.envelopes - } -} - -impl DerefMut for Collection { - fn deref_mut(&mut self) -> &mut FnvHashMap { - &mut self.envelopes + pub fn get_env_mut<'g>(&'g mut self, env_hash: EnvelopeHash) -> EnvelopeRefMut<'g> { + let guard = self.envelopes.write().unwrap(); + EnvelopeRefMut { guard, env_hash } + } + + pub fn contains_key(&self, env_hash: &EnvelopeHash) -> bool { + self.envelopes.read().unwrap().contains_key(env_hash) } } diff --git a/melib/src/thread.rs b/melib/src/thread.rs index a4ad62cd1..cd25136aa 100644 --- a/melib/src/thread.rs +++ b/melib/src/thread.rs @@ -50,8 +50,9 @@ use std::ops::Index; use std::result::Result as StdResult; use std::str::FromStr; use std::string::ToString; +use std::sync::{Arc, RwLock}; -type Envelopes = FnvHashMap; +type Envelopes = Arc>>; #[derive(PartialEq, Hash, Eq, Copy, Clone, Serialize, Deserialize, Default)] pub struct ThreadHash(Uuid); @@ -485,6 +486,7 @@ impl ThreadNode { buf: &FnvHashMap, envelopes: &Envelopes, ) -> usize { + let envelopes = envelopes.read().unwrap(); match sort { (SortField::Date, SortOrder::Asc) => { match vec.binary_search_by(|probe| buf[&probe].date.cmp(&buf[&child].date)) { @@ -682,25 +684,25 @@ impl Threads { x_root } - pub fn new(envelopes: &mut Envelopes) -> Threads { + pub fn new(length: usize) -> Threads { /* To reconstruct thread information from the mails we need: */ /* a vector to hold thread members */ let thread_nodes: FnvHashMap = FnvHashMap::with_capacity_and_hasher( - (envelopes.len() as f64 * 1.2) as usize, + (length as f64 * 1.2) as usize, Default::default(), ); /* A hash table of Message IDs */ let message_ids: FnvHashMap, ThreadHash> = - FnvHashMap::with_capacity_and_hasher(envelopes.len(), Default::default()); + FnvHashMap::with_capacity_and_hasher(length, Default::default()); /* A hash set of Message IDs we haven't encountered yet as an Envelope */ let missing_message_ids: FnvHashSet> = - FnvHashSet::with_capacity_and_hasher(envelopes.len(), Default::default()); + FnvHashSet::with_capacity_and_hasher(length, Default::default()); /* A hash set of Message IDs we have encountered as a MessageID */ let message_ids_set: FnvHashSet> = - FnvHashSet::with_capacity_and_hasher(envelopes.len(), Default::default()); + FnvHashSet::with_capacity_and_hasher(length, Default::default()); let hash_set: FnvHashSet = - FnvHashSet::with_capacity_and_hasher(envelopes.len(), Default::default()); + FnvHashSet::with_capacity_and_hasher(length, Default::default()); Threads { thread_nodes, @@ -754,12 +756,12 @@ impl Threads { }; self.thread_nodes.get_mut(&thread_hash).unwrap().message = Some(new_hash); - self.thread_nodes.get_mut(&thread_hash).unwrap().has_unseen = !envelopes[&new_hash] - .is_seen() - || self.thread_nodes[&thread_hash] - .children - .iter() - .fold(false, |acc, x| acc || self.thread_nodes[x].has_unseen); + self.thread_nodes.get_mut(&thread_hash).unwrap().has_unseen = + !envelopes.read().unwrap()[&new_hash].is_seen() + || self.thread_nodes[&thread_hash] + .children + .iter() + .fold(false, |acc, x| acc || self.thread_nodes[x].has_unseen); let mut thread_hash_iter = thread_hash; while self.thread_nodes[&thread_hash_iter].parent.is_some() { @@ -802,18 +804,20 @@ impl Threads { } pub fn amend(&mut self, envelopes: &mut Envelopes) { - let new_hash_set = FnvHashSet::from_iter(envelopes.keys().cloned()); + let envelopes_lck = envelopes.read().unwrap(); + let new_hash_set = FnvHashSet::from_iter(envelopes_lck.keys().cloned()); let difference: Vec = self.hash_set.difference(&new_hash_set).cloned().collect(); for h in difference { self.remove(h); } + drop(envelopes_lck); let difference: Vec = new_hash_set.difference(&self.hash_set).cloned().collect(); for h in difference { - debug!("inserting {}", envelopes[&h].subject()); + //debug!("inserting {}", envelopes_lck[&h].subject()); self.insert(envelopes, h); } } @@ -825,6 +829,7 @@ impl Threads { env_hash: EnvelopeHash, envelopes: &Envelopes, ) { + let envelopes = envelopes.read().unwrap(); let mut subject = envelopes[&env_hash].subject(); let mut subject = subject.to_mut().as_bytes(); let stripped_subject = subject.strip_prefixes(); @@ -861,17 +866,18 @@ impl Threads { } pub fn insert(&mut self, envelopes: &mut Envelopes, env_hash: EnvelopeHash) { + let envelopes_lck = envelopes.read().unwrap(); if self .message_ids - .contains_key(envelopes[&env_hash].message_id().raw()) + .contains_key(envelopes_lck[&env_hash].message_id().raw()) && !self .missing_message_ids - .contains(envelopes[&env_hash].message_id().raw()) + .contains(envelopes_lck[&env_hash].message_id().raw()) { return; } - let reply_to_id: Option = envelopes[&env_hash] + let reply_to_id: Option = envelopes_lck[&env_hash] .in_reply_to() .map(crate::email::StrBuild::raw) .and_then(|r| self.message_ids.get(r).cloned()); @@ -881,24 +887,28 @@ impl Threads { ThreadNode { message: Some(env_hash), parent: reply_to_id, - date: envelopes[&env_hash].date(), - has_unseen: !envelopes[&env_hash].is_seen(), + date: envelopes_lck[&env_hash].date(), + has_unseen: !envelopes_lck[&env_hash].is_seen(), ..ThreadNode::new(new_id) }, ); self.message_ids - .insert(envelopes[&env_hash].message_id().raw().to_vec(), new_id); - self.message_ids_set - .insert(envelopes[&env_hash].message_id().raw().to_vec().to_vec()); + .insert(envelopes_lck[&env_hash].message_id().raw().to_vec(), new_id); + self.message_ids_set.insert( + envelopes_lck[&env_hash] + .message_id() + .raw() + .to_vec() + .to_vec(), + ); self.missing_message_ids - .remove(envelopes[&env_hash].message_id().raw()); - envelopes.get_mut(&env_hash).unwrap().set_thread(new_id); + .remove(envelopes_lck[&env_hash].message_id().raw()); self.hash_set.insert(env_hash); if let Some(reply_to_id) = reply_to_id { self.union(reply_to_id, new_id); make!((reply_to_id) parent of (new_id), &mut self.thread_nodes); } else { - if let Some(r) = envelopes[&env_hash] + if let Some(r) = envelopes_lck[&env_hash] .in_reply_to() .map(crate::email::StrBuild::raw) { @@ -906,7 +916,7 @@ impl Threads { self.thread_nodes.insert( reply_to_id, ThreadNode { - date: envelopes[&env_hash].date(), + date: envelopes_lck[&env_hash].date(), thread_group: reply_to_id, ..ThreadNode::new(reply_to_id) }, @@ -919,23 +929,31 @@ impl Threads { } self.tree_insert_root(new_id, envelopes); } + drop(envelopes_lck); self.update_show_subject(new_id, env_hash, envelopes); + envelopes + .write() + .unwrap() + .get_mut(&env_hash) + .unwrap() + .set_thread(new_id); } /* Insert or update */ pub fn insert_reply(&mut self, envelopes: &mut Envelopes, env_hash: EnvelopeHash) -> bool { - let reply_to_id: Option = envelopes[&env_hash] + let mut envelopes_lck = envelopes.write().unwrap(); + let reply_to_id: Option = envelopes_lck[&env_hash] .in_reply_to() .map(crate::email::StrBuild::raw) .and_then(|r| self.message_ids.get(r).cloned()); if let Some(id) = self .message_ids - .get(envelopes[&env_hash].message_id().raw()) + .get(envelopes_lck[&env_hash].message_id().raw()) .cloned() { self.thread_nodes.entry(id).and_modify(|n| { n.message = Some(env_hash); - n.date = envelopes[&env_hash].date(); + n.date = envelopes_lck[&env_hash].date(); n.pruned = false; if n.parent.is_none() { if let Some(reply_to_id) = reply_to_id { @@ -951,13 +969,19 @@ impl Threads { } self.message_ids - .insert(envelopes[&env_hash].message_id().raw().to_vec(), id); - self.message_ids_set - .insert(envelopes[&env_hash].message_id().raw().to_vec().to_vec()); + .insert(envelopes_lck[&env_hash].message_id().raw().to_vec(), id); + self.message_ids_set.insert( + envelopes_lck[&env_hash] + .message_id() + .raw() + .to_vec() + .to_vec(), + ); self.missing_message_ids - .remove(envelopes[&env_hash].message_id().raw()); - envelopes.get_mut(&env_hash).unwrap().set_thread(id); + .remove(envelopes_lck[&env_hash].message_id().raw()); + envelopes_lck.get_mut(&env_hash).unwrap().set_thread(id); self.hash_set.insert(env_hash); + drop(envelopes_lck); if self.thread_nodes[&id].parent.is_none() { self.tree_insert_root(id, envelopes); } @@ -978,21 +1002,27 @@ impl Threads { ThreadNode { message: Some(env_hash), parent: Some(reply_to_id), - date: envelopes[&env_hash].date(), - has_unseen: !envelopes[&env_hash].is_seen(), + date: envelopes_lck[&env_hash].date(), + has_unseen: !envelopes_lck[&env_hash].is_seen(), ..ThreadNode::new(new_id) }, ); self.message_ids - .insert(envelopes[&env_hash].message_id().raw().to_vec(), new_id); - self.message_ids_set - .insert(envelopes[&env_hash].message_id().raw().to_vec().to_vec()); + .insert(envelopes_lck[&env_hash].message_id().raw().to_vec(), new_id); + self.message_ids_set.insert( + envelopes_lck[&env_hash] + .message_id() + .raw() + .to_vec() + .to_vec(), + ); self.missing_message_ids - .remove(envelopes[&env_hash].message_id().raw()); - envelopes.get_mut(&env_hash).unwrap().set_thread(new_id); + .remove(envelopes_lck[&env_hash].message_id().raw()); + envelopes_lck.get_mut(&env_hash).unwrap().set_thread(new_id); self.hash_set.insert(env_hash); self.union(reply_to_id, new_id); make!((reply_to_id) parent of (new_id), &mut self.thread_nodes); + drop(envelopes_lck); self.update_show_subject(new_id, env_hash, envelopes); true } else { @@ -1073,6 +1103,7 @@ impl Threads { sort: (SortField, SortOrder), envelopes: &Envelopes, ) { + let envelopes = envelopes.read().unwrap(); vec.sort_by(|b, a| match sort { (SortField::Date, SortOrder::Desc) => { let a = &self.thread_nodes[&a]; @@ -1148,6 +1179,7 @@ impl Threads { } fn inner_sort_by(&self, sort: (SortField, SortOrder), envelopes: &Envelopes) { let tree = &mut self.tree_index.borrow_mut(); + let envelopes = envelopes.read().unwrap(); tree.sort_by(|b, a| match sort { (SortField::Date, SortOrder::Desc) => { let a = &self.thread_nodes[&a]; diff --git a/ui/src/cache.rs b/ui/src/cache.rs index a54b65e11..22c8f33ee 100644 --- a/ui/src/cache.rs +++ b/ui/src/cache.rs @@ -50,6 +50,7 @@ enum CacheType { Sqlite3, } +/* pub struct Cache { collection: Collection, kind: CacheType, @@ -108,3 +109,4 @@ impl Cache { &self.collection.threads[&f].thread_nodes()[&h] } } +*/ diff --git a/ui/src/components/mail/compose.rs b/ui/src/components/mail/compose.rs index db6df6ef4..22f9ec685 100644 --- a/ui/src/components/mail/compose.rs +++ b/ui/src/components/mail/compose.rs @@ -169,9 +169,9 @@ impl Composer { pub fn edit(account_pos: usize, h: EnvelopeHash, context: &Context) -> Result { let mut ret = Composer::default(); let op = context.accounts[account_pos].operation(h); - let envelope: &Envelope = context.accounts[account_pos].get_env(&h); + let envelope: EnvelopeRef = context.accounts[account_pos].collection.get_env(h); - ret.draft = Draft::edit(envelope, op)?; + ret.draft = Draft::edit(&envelope, op)?; ret.account_cursor = account_pos; Ok(ret) @@ -187,10 +187,10 @@ impl Composer { let thread_nodes = &threads.thread_nodes(); let mut ret = Composer::default(); let p = &thread_nodes[&msg]; - let parent_message = &account.collection[&p.message().unwrap()]; + let parent_message = account.collection.get_env(p.message().unwrap()); /* If message is from a mailing list and we detect a List-Post header, ask user if they * want to reply to the mailing list or the submitter of the message */ - if let Some(actions) = list_management::detect(parent_message) { + if let Some(actions) = list_management::detect(&parent_message) { if let Some(post) = actions.post { /* Try to parse header value in this order * - @@ -224,16 +224,24 @@ impl Composer { let mut op = account.operation(parent_message.hash()); let parent_bytes = op.as_bytes(); - ret.draft = Draft::new_reply(parent_message, parent_bytes.unwrap()); + ret.draft = Draft::new_reply(&parent_message, parent_bytes.unwrap()); ret.draft.headers_mut().insert( "Subject".into(), if p.show_subject() { format!( "Re: {}", - account.get_env(&p.message().unwrap()).subject().clone() + account + .collection + .get_env(p.message().unwrap()) + .subject() + .clone() ) } else { - account.get_env(&p.message().unwrap()).subject().into() + account + .collection + .get_env(p.message().unwrap()) + .subject() + .into() }, ); diff --git a/ui/src/components/mail/listing.rs b/ui/src/components/mail/listing.rs index fca74936c..d68b87423 100644 --- a/ui/src/components/mail/listing.rs +++ b/ui/src/components/mail/listing.rs @@ -579,13 +579,15 @@ impl Component for Listing { } else { return Some(String::new()); }; + let envelopes = account.collection.envelopes.clone(); + let envelopes = envelopes.read().unwrap(); format!( "Mailbox: {}, Messages: {}, New: {}", m.folder.name(), m.envelopes.len(), m.envelopes .iter() - .map(|h| &account.collection[&h]) + .map(|h| &envelopes[&h]) .filter(|e| !e.is_seen()) .count() ) @@ -714,8 +716,8 @@ impl Listing { .unwrap() .envelopes .iter() - .filter_map(|h| { - if account.collection[&h].is_seen() { + .filter_map(|&h| { + if account.collection.get_env(h).is_seen() { None } else { Some(()) diff --git a/ui/src/components/mail/listing/compact.rs b/ui/src/components/mail/listing/compact.rs index 993267794..198010e5e 100644 --- a/ui/src/components/mail/listing/compact.rs +++ b/ui/src/components/mail/listing/compact.rs @@ -364,10 +364,10 @@ impl ListingTrait for CompactListing { Ok(results) => { let threads = &account.collection.threads[&folder_hash]; for env_hash in results { - if !account.collection.envelopes.contains_key(&env_hash) { + if !account.collection.contains_key(&env_hash) { continue; } - let env_hash_thread_hash = account.get_env(&env_hash).thread(); + let env_hash_thread_hash = account.collection.get_env(env_hash).thread(); if !threads.thread_nodes.contains_key(&env_hash_thread_hash) { continue; } @@ -388,7 +388,7 @@ impl ListingTrait for CompactListing { threads.vec_inner_sort_by( &mut self.filtered_selection, self.sort, - &context.accounts[self.cursor_pos.0].collection, + &context.accounts[self.cursor_pos.0].collection.envelopes, ); self.new_cursor_pos.2 = std::cmp::min(self.filtered_selection.len() - 1, self.cursor_pos.2); @@ -469,7 +469,11 @@ impl CompactListing { id: ComponentId::new_v4(), } } - fn make_entry_string(e: &Envelope, thread_node: &ThreadNode, is_snoozed: bool) -> EntryStrings { + fn make_entry_string( + e: EnvelopeRef, + thread_node: &ThreadNode, + is_snoozed: bool, + ) -> EntryStrings { if thread_node.len() > 0 { EntryStrings { date: DateString(ConversationsListing::format_date(thread_node)), @@ -560,7 +564,7 @@ impl CompactListing { let mut rows = Vec::with_capacity(1024); let mut min_width = (0, 0, 0, 0, 0); - threads.sort_by(self.sort, self.subsort, &account.collection); + threads.sort_by(self.sort, self.subsort, &account.collection.envelopes); let mut refresh_mailbox = false; let threads_iter = if self.filter_term.is_empty() { @@ -594,7 +598,8 @@ impl CompactListing { panic!(); } - let root_envelope: &Envelope = &context.accounts[self.cursor_pos.0].get_env(&i); + let root_envelope: EnvelopeRef = + context.accounts[self.cursor_pos.0].collection.get_env(i); let entry_strings = CompactListing::make_entry_string( root_envelope, @@ -750,8 +755,9 @@ impl CompactListing { } match ( threads.is_snoozed(root_idx), - &context.accounts[self.cursor_pos.0] - .get_env(&i) + context.accounts[self.cursor_pos.0] + .collection + .get_env(i) .has_attachments(), ) { (true, true) => { @@ -835,11 +841,11 @@ impl CompactListing { } } for env_hash in envs_to_set { + let hash = account.collection.get_env(env_hash).hash(); + let op = account.operation(hash); + let mut envelope: EnvelopeRefMut = account.collection.get_env_mut(env_hash); match a { ListingAction::SetSeen => { - let hash = account.get_env(&env_hash).hash(); - let op = account.operation(hash); - let envelope: &mut Envelope = &mut account.get_env_mut(&env_hash); if let Err(e) = envelope.set_seen(op) { context.replies.push_back(UIEvent::StatusEvent( StatusEvent::DisplayMessage(e.to_string()), @@ -848,19 +854,19 @@ impl CompactListing { self.row_updates.push(thread_hash); } ListingAction::SetUnseen => { - let hash = account.get_env(&env_hash).hash(); - let op = account.operation(hash); - let envelope: &mut Envelope = &mut account.get_env_mut(&env_hash); if let Err(e) = envelope.set_unseen(op) { context.replies.push_back(UIEvent::StatusEvent( StatusEvent::DisplayMessage(e.to_string()), )); } - self.row_updates.push(thread_hash); } - ListingAction::Delete => { /* do nothing */ } + ListingAction::Delete => { + /* do nothing */ + continue; + } _ => unreachable!(), } + self.row_updates.push(thread_hash); } } } @@ -1009,10 +1015,10 @@ impl Component for CompactListing { let account = &context.accounts[self.cursor_pos.0]; let folder_hash = account[self.cursor_pos.1].unwrap().folder.hash(); let threads = &account.collection.threads[&folder_hash]; - if !account.collection.envelopes.contains_key(&new_hash) { + if !account.collection.contains_key(&new_hash) { return false; } - let new_env_thread_hash = account.get_env(new_hash).thread(); + let new_env_thread_hash = account.collection.get_env(*new_hash).thread(); if !threads.thread_nodes.contains_key(&new_env_thread_hash) { return false; } @@ -1094,7 +1100,7 @@ impl Component for CompactListing { threads.vec_inner_sort_by( &mut self.filtered_selection, self.sort, - &context.accounts[self.cursor_pos.0].collection, + &context.accounts[self.cursor_pos.0].collection.envelopes, ); self.dirty = true; } else { diff --git a/ui/src/components/mail/listing/conversations.rs b/ui/src/components/mail/listing/conversations.rs index 45c91fff0..88ab1373b 100644 --- a/ui/src/components/mail/listing/conversations.rs +++ b/ui/src/components/mail/listing/conversations.rs @@ -355,10 +355,10 @@ impl ListingTrait for ConversationsListing { Ok(results) => { let threads = &account.collection.threads[&folder_hash]; for env_hash in results { - if !account.collection.envelopes.contains_key(&env_hash) { + if !account.collection.contains_key(&env_hash) { continue; } - let env_hash_thread_hash = account.get_env(&env_hash).thread(); + let env_hash_thread_hash = account.collection.get_env(env_hash).thread(); if !threads.thread_nodes.contains_key(&env_hash_thread_hash) { continue; } @@ -379,7 +379,7 @@ impl ListingTrait for ConversationsListing { threads.vec_inner_sort_by( &mut self.filtered_selection, self.sort, - &context.accounts[self.cursor_pos.0].collection, + &context.accounts[self.cursor_pos.0].collection.envelopes, ); self.new_cursor_pos.2 = std::cmp::min(self.filtered_selection.len() - 1, self.cursor_pos.2); @@ -555,7 +555,7 @@ impl ConversationsListing { let mut rows = Vec::with_capacity(1024); let mut max_entry_columns = 0; - threads.sort_by(self.sort, self.subsort, &account.collection); + threads.sort_by(self.sort, self.subsort, &account.collection.envelopes); let mut refresh_mailbox = false; let threads_iter = if self.filter_term.is_empty() { @@ -589,7 +589,8 @@ impl ConversationsListing { panic!(); } - let root_envelope: &Envelope = &context.accounts[self.cursor_pos.0].get_env(&i); + let root_envelope: &EnvelopeRef = + &context.accounts[self.cursor_pos.0].collection.get_env(i); let strings = ConversationsListing::make_entry_string( root_envelope, @@ -808,32 +809,31 @@ impl ConversationsListing { } } for env_hash in envs_to_set { + let hash = account.collection.get_env(env_hash).hash(); + let op = account.operation(hash); + let mut envelope: EnvelopeRefMut = account.collection.get_env_mut(env_hash); match a { ListingAction::SetSeen => { - let hash = account.get_env(&env_hash).hash(); - let op = account.operation(hash); - let envelope: &mut Envelope = &mut account.get_env_mut(&env_hash); if let Err(e) = envelope.set_seen(op) { context.replies.push_back(UIEvent::StatusEvent( StatusEvent::DisplayMessage(e.to_string()), )); } - self.row_updates.push(thread_hash); } ListingAction::SetUnseen => { - let hash = account.get_env(&env_hash).hash(); - let op = account.operation(hash); - let envelope: &mut Envelope = &mut account.get_env_mut(&env_hash); if let Err(e) = envelope.set_unseen(op) { context.replies.push_back(UIEvent::StatusEvent( StatusEvent::DisplayMessage(e.to_string()), )); } - self.row_updates.push(thread_hash); } - ListingAction::Delete => { /* do nothing */ } + ListingAction::Delete => { + /* do nothing */ + continue; + } _ => unreachable!(), } + self.row_updates.push(thread_hash); } } } @@ -1049,10 +1049,10 @@ impl Component for ConversationsListing { let account = &context.accounts[self.cursor_pos.0]; let folder_hash = account[self.cursor_pos.1].unwrap().folder.hash(); let threads = &account.collection.threads[&folder_hash]; - if !account.collection.envelopes.contains_key(&new_hash) { + if !account.collection.contains_key(&new_hash) { return false; } - let new_env_thread_hash = account.get_env(new_hash).thread(); + let new_env_thread_hash = account.collection.get_env(*new_hash).thread(); if !threads.thread_nodes.contains_key(&new_env_thread_hash) { return false; } @@ -1133,7 +1133,7 @@ impl Component for ConversationsListing { threads.vec_inner_sort_by( &mut self.filtered_selection, self.sort, - &context.accounts[self.cursor_pos.0].collection, + &context.accounts[self.cursor_pos.0].collection.envelopes, ); self.dirty = true; } else { diff --git a/ui/src/components/mail/listing/plain.rs b/ui/src/components/mail/listing/plain.rs index 4a1c941c1..d71ae19b9 100644 --- a/ui/src/components/mail/listing/plain.rs +++ b/ui/src/components/mail/listing/plain.rs @@ -97,7 +97,7 @@ impl ListingTrait for PlainListing { } fn highlight_line(&mut self, grid: &mut CellBuffer, area: Area, idx: usize, context: &Context) { let account = &context.accounts[self.cursor_pos.0]; - let envelope: &Envelope = &account.get_env(&self.local_collection[idx]); + let envelope: EnvelopeRef = account.collection.get_env(self.local_collection[idx]); let fg_color = if !envelope.is_seen() { Color::Byte(0) @@ -323,27 +323,28 @@ impl PlainListing { ); return; } - self.local_collection = account.collection.keys().cloned().collect(); + let envelopes = account.collection.envelopes.read().unwrap(); + self.local_collection = envelopes.keys().cloned().collect(); let sort = self.sort; self.local_collection.sort_by(|a, b| match sort { (SortField::Date, SortOrder::Desc) => { - let ma = &account.get_env(a); - let mb = &account.get_env(b); + let ma = &envelopes[a]; + let mb = &envelopes[b]; mb.date().cmp(&ma.date()) } (SortField::Date, SortOrder::Asc) => { - let ma = &account.get_env(a); - let mb = &account.get_env(b); + let ma = &envelopes[a]; + let mb = &envelopes[b]; ma.date().cmp(&mb.date()) } (SortField::Subject, SortOrder::Desc) => { - let ma = &account.get_env(a); - let mb = &account.get_env(b); + let ma = &envelopes[a]; + let mb = &envelopes[b]; ma.subject().cmp(&mb.subject()) } (SortField::Subject, SortOrder::Asc) => { - let ma = &account.get_env(a); - let mb = &account.get_env(b); + let ma = &envelopes[a]; + let mb = &envelopes[b]; mb.subject().cmp(&ma.subject()) } }); @@ -353,9 +354,9 @@ impl PlainListing { let widths: (usize, usize, usize); for idx in 0..self.local_collection.len() { - let envelope: &Envelope = &account.get_env(&self.local_collection[idx]); + let envelope: EnvelopeRef = account.collection.get_env(self.local_collection[idx]); - let strings = PlainListing::make_entry_string(envelope, idx); + let strings = PlainListing::make_entry_string(&envelope, idx); min_width.0 = cmp::max(min_width.0, strings.0.len()); /* index */ min_width.1 = cmp::max(min_width.1, strings.2.split_graphemes().len()); /* date */ min_width.2 = cmp::max(min_width.2, strings.3.split_graphemes().len()); /* subject */ @@ -381,7 +382,7 @@ impl PlainListing { break; } /* Write an entire line for each envelope entry. */ - let envelope: &Envelope = &account.get_env(&self.local_collection[idx]); + let envelope: EnvelopeRef = account.collection.get_env(self.local_collection[idx]); let fg_color = if !envelope.is_seen() { Color::Byte(0) @@ -533,9 +534,9 @@ impl Component for PlainListing { if self.length == 0 { false } else { - let account = &mut context.accounts[self.cursor_pos.0]; - let envelope: &mut Envelope = - &mut account.get_env_mut(&self.local_collection[idx]); + let account = &context.accounts[self.cursor_pos.0]; + let envelope: EnvelopeRef = + account.collection.get_env(self.local_collection[idx]); !envelope.is_seen() } }; diff --git a/ui/src/components/mail/listing/thread.rs b/ui/src/components/mail/listing/thread.rs index 5cc666a75..390652a09 100644 --- a/ui/src/components/mail/listing/thread.rs +++ b/ui/src/components/mail/listing/thread.rs @@ -177,8 +177,9 @@ impl ListingTrait for ThreadListing { } if self.locations[idx] != 0 { - let envelope: &Envelope = - &context.accounts[self.cursor_pos.0].get_env(&self.locations[idx]); + let envelope: EnvelopeRef = context.accounts[self.cursor_pos.0] + .collection + .get_env(self.locations[idx]); let fg_color = if !envelope.is_seen() { Color::Byte(0) @@ -297,7 +298,7 @@ impl ThreadListing { let mut indentations: Vec = Vec::with_capacity(6); let mut thread_idx = 0; // needed for alternate thread colors /* Draw threaded view. */ - threads.sort_by(self.sort, self.subsort, &account.collection); + threads.sort_by(self.sort, self.subsort, &account.collection.envelopes); let thread_nodes: &FnvHashMap = &threads.thread_nodes(); let mut iter = threads.threads_iter().peekable(); /* This is just a desugared for loop so that we can use .peek() */ @@ -309,7 +310,8 @@ impl ThreadListing { thread_idx += 1; } if thread_node.has_message() { - let envelope: &Envelope = &account.get_env(&thread_node.message().unwrap()); + let envelope: EnvelopeRef = + account.collection.get_env(thread_node.message().unwrap()); self.locations.push(envelope.hash()); let fg_color = if !envelope.is_seen() { Color::Byte(0) @@ -325,7 +327,7 @@ impl ThreadListing { }; let (x, _) = write_string_to_grid( &ThreadListing::make_thread_entry( - envelope, + &envelope, idx, indentation, thread_hash, @@ -378,8 +380,9 @@ impl ThreadListing { return; } if self.locations[idx] != 0 { - let envelope: &Envelope = - &context.accounts[self.cursor_pos.0].get_env(&self.locations[idx]); + let envelope: EnvelopeRef = context.accounts[self.cursor_pos.0] + .collection + .get_env(self.locations[idx]); let fg_color = if !envelope.is_seen() { Color::Byte(0) @@ -509,8 +512,10 @@ impl Component for ThreadListing { if self.length == 0 { false } else { - let account = &mut context.accounts[self.cursor_pos.0]; - let envelope: &Envelope = &account.get_env(&self.locations[self.cursor_pos.2]); + let account = &context.accounts[self.cursor_pos.0]; + let envelope: EnvelopeRef = account + .collection + .get_env(self.locations[self.cursor_pos.2]); envelope.is_seen() } }; diff --git a/ui/src/components/mail/view.rs b/ui/src/components/mail/view.rs index 4a9b143b5..5cfd5dbcc 100644 --- a/ui/src/components/mail/view.rs +++ b/ui/src/components/mail/view.rs @@ -317,12 +317,13 @@ impl Component for MailView { return; } let (hash, is_seen) = { - let envelope: &Envelope = &account.get_env(&self.coordinates.2); + let envelope: EnvelopeRef = account.collection.get_env(self.coordinates.2); (envelope.hash(), envelope.is_seen()) }; if !is_seen { let op = account.operation(hash); - let envelope: &mut Envelope = &mut account.get_env_mut(&self.coordinates.2); + let mut envelope: EnvelopeRefMut = + account.collection.get_env_mut(self.coordinates.2); if let Err(e) = envelope.set_seen(op) { context .replies @@ -332,7 +333,7 @@ impl Component for MailView { )))); } } - let envelope: &Envelope = &account.get_env(&self.coordinates.2); + let envelope: EnvelopeRef = account.collection.get_env(self.coordinates.2); let header_fg = if context.settings.terminal.theme == "light" { Color::Black @@ -459,7 +460,7 @@ impl Component for MailView { ref archive, ref post, ref unsubscribe, - }) = list_management::detect(envelope) + }) = list_management::detect(&envelope) { let mut x = get_x(upper_left); y += 1; @@ -577,7 +578,7 @@ impl Component for MailView { if self.dirty { let body = { let account = &mut context.accounts[self.coordinates.0]; - let envelope: &Envelope = &account.get_env(&self.coordinates.2); + let envelope: EnvelopeRef = account.collection.get_env(self.coordinates.2); let op = account.operation(envelope.hash()); match envelope.body(op) { Ok(body) => body, @@ -615,7 +616,7 @@ impl Component for MailView { ViewMode::Raw => { let text = { let account = &mut context.accounts[self.coordinates.0]; - let envelope: &Envelope = &account.get_env(&self.coordinates.2); + let envelope: EnvelopeRef = account.collection.get_env(self.coordinates.2); let mut op = account.operation(envelope.hash()); op.as_bytes() .map(|v| String::from_utf8_lossy(v).into_owned()) @@ -714,7 +715,7 @@ impl Component for MailView { match *event { UIEvent::Input(Key::Char('c')) if !self.mode.is_contact_selector() => { let account = &mut context.accounts[self.coordinates.0]; - let envelope: &Envelope = &account.get_env(&self.coordinates.2); + let envelope: EnvelopeRef = account.collection.get_env(self.coordinates.2); let mut entries = Vec::new(); for addr in envelope.from().iter().chain(envelope.to().iter()) { @@ -723,6 +724,7 @@ impl Component for MailView { new_card.set_name(addr.get_display_name()); entries.push((new_card, format!("{}", addr))); } + drop(envelope); self.mode = ViewMode::ContactSelector(Selector::new( "select contacts to add", entries, @@ -777,7 +779,7 @@ impl Component for MailView { { let account = &mut context.accounts[self.coordinates.0]; - let envelope: &Envelope = &account.get_env(&self.coordinates.2); + let envelope: EnvelopeRef = account.collection.get_env(self.coordinates.2); let op = account.operation(envelope.hash()); let attachments = match envelope.body(op) { @@ -912,7 +914,7 @@ impl Component for MailView { .push_back(UIEvent::StatusEvent(StatusEvent::BufClear)); let url = { let account = &mut context.accounts[self.coordinates.0]; - let envelope: &Envelope = &account.get_env(&self.coordinates.2); + let envelope: EnvelopeRef = account.collection.get_env(self.coordinates.2); let finder = LinkFinder::new(); let op = account.operation(envelope.hash()); let t = match envelope.body(op) { @@ -973,8 +975,8 @@ impl Component for MailView { * arrive */ return true; } - let envelope: &Envelope = &account.get_env(&self.coordinates.2); - if let Some(actions) = list_management::detect(envelope) { + let envelope: EnvelopeRef = account.collection.get_env(self.coordinates.2); + if let Some(actions) = list_management::detect(&envelope) { match e { MailingListAction::ListPost if actions.post.is_some() => { /* open composer */ diff --git a/ui/src/components/mail/view/thread.rs b/ui/src/components/mail/view/thread.rs index a5100e667..26f69ee8d 100644 --- a/ui/src/components/mail/view/thread.rs +++ b/ui/src/components/mail/view/thread.rs @@ -165,7 +165,7 @@ impl ThreadView { self.entries.clear(); for (line, (ind, thread_hash)) in thread_iter.enumerate() { let entry = if let Some(msg_hash) = threads.thread_nodes()[&thread_hash].message() { - let seen: bool = account.get_env(&msg_hash).is_seen(); + let seen: bool = account.collection.get_env(msg_hash).is_seen(); self.make_entry((ind, thread_hash, line), msg_hash, seen) } else { continue; @@ -190,7 +190,9 @@ impl ThreadView { let mut highlight_reply_subjects: Vec> = Vec::with_capacity(self.entries.len()); for e in &mut self.entries { - let envelope: &Envelope = &context.accounts[self.coordinates.0].get_env(&e.msg_hash); + let envelope: EnvelopeRef = context.accounts[self.coordinates.0] + .collection + .get_env(e.msg_hash); let thread_node = &threads.thread_nodes()[&e.index.1]; let string = if thread_node.show_subject() { let subject = envelope.subject(); @@ -265,8 +267,9 @@ impl ThreadView { true, ); { - let envelope: &Envelope = - &context.accounts[self.coordinates.0].get_env(&e.msg_hash); + let envelope: EnvelopeRef = context.accounts[self.coordinates.0] + .collection + .get_env(e.msg_hash); if envelope.has_attachments() { content[(e.index.0 * 4 + e.heading.grapheme_width(), 2 * y)] .set_fg(Color::Byte(103)); @@ -342,8 +345,9 @@ impl ThreadView { false, ); { - let envelope: &Envelope = - &context.accounts[self.coordinates.0].get_env(&e.msg_hash); + let envelope: EnvelopeRef = context.accounts[self.coordinates.0] + .collection + .get_env(e.msg_hash); if envelope.has_attachments() { content[(e.index.0 * 4 + e.heading.grapheme_width(), 2 * y)] .set_fg(Color::Byte(103)); @@ -624,7 +628,7 @@ impl ThreadView { } threads.thread_nodes()[&iter_ptr].message().unwrap() }; - let envelope: &Envelope = account.get_env(&i); + let envelope: EnvelopeRef = account.collection.get_env(i); let (x, y) = write_string_to_grid( &envelope.subject(), @@ -710,7 +714,7 @@ impl ThreadView { } threads.thread_nodes()[&iter_ptr].message().unwrap() }; - let envelope: &Envelope = account.get_env(&i); + let envelope: EnvelopeRef = account.collection.get_env(i); let (x, y) = write_string_to_grid( &envelope.subject(), @@ -954,7 +958,7 @@ impl Component for ThreadView { .message() .unwrap() }; - let envelope: &Envelope = &account.get_env(&i); + let envelope: EnvelopeRef = account.collection.get_env(i); let op = account.operation(envelope.hash()); debug!( "sending action edit for {}, {}", @@ -1061,7 +1065,7 @@ impl Component for ThreadView { for e in self.entries.iter_mut() { if e.msg_hash == *old_hash { e.msg_hash = *new_hash; - let seen: bool = account.get_env(&new_hash).is_seen(); + let seen: bool = account.collection.get_env(*new_hash).is_seen(); if seen != e.seen { self.dirty = true; } diff --git a/ui/src/components/utilities.rs b/ui/src/components/utilities.rs index 3686b5516..48108d504 100644 --- a/ui/src/components/utilities.rs +++ b/ui/src/components/utilities.rs @@ -1533,7 +1533,8 @@ impl Component for Tabbed { format!( "Failed to open envelope {}: {}", context.accounts[account_pos] - .get_env(&msg) + .collection + .get_env(msg) .message_id_display(), e.to_string() ), diff --git a/ui/src/conf/accounts.rs b/ui/src/conf/accounts.rs index 7ee254394..55ae3d6fa 100644 --- a/ui/src/conf/accounts.rs +++ b/ui/src/conf/accounts.rs @@ -484,7 +484,7 @@ impl Account { } RefreshEventKind::Create(envelope) => { let env_hash = envelope.hash(); - if self.collection.envelopes.contains_key(&env_hash) + if self.collection.contains_key(&env_hash) && mailbox!(&folder_hash, self.folders) .envelopes .contains(&env_hash) @@ -492,6 +492,14 @@ impl Account { return None; } mailbox!(&folder_hash, self.folders).insert(env_hash); + let (is_seen, is_draft) = + { (envelope.is_seen(), envelope.flags().contains(Flag::DRAFT)) }; + let (subject, from) = { + ( + envelope.subject().into_owned(), + envelope.field_from_to_string(), + ) + }; self.collection.insert(*envelope, folder_hash); if self .sent_folder @@ -507,20 +515,23 @@ impl Account { if folder_conf.ignore.is_true() { return Some(UIEvent::MailboxUpdate((self.index, folder_hash))); } - let (_, thread_node) = self.mail_and_thread(env_hash, folder_hash); + + let thread_node = { + let thread_hash = &mut self.collection.get_env(env_hash).thread(); + &self.collection.threads[&folder_hash][&thread_hash] + }; if thread_node.snoozed() { return Some(UIEvent::MailboxUpdate((self.index, folder_hash))); } - let env = self.get_env(&env_hash); - if env.is_seen() || env.flags().contains(Flag::DRAFT) { + if is_seen || is_draft { return Some(UIEvent::MailboxUpdate((self.index, folder_hash))); } return Some(Notification( - Some(format!("new e-mail from: {}", env.field_from_to_string())), + Some(format!("new e-mail from: {}", from)), format!( "{}\n{} {}", - env.subject(), + subject, self.name, ref_folders[&folder_hash].name(), ), @@ -725,12 +736,6 @@ impl Account { } } - pub fn get_env(&self, h: &EnvelopeHash) -> &Envelope { - &self.collection[h] - } - pub fn get_env_mut(&mut self, h: &EnvelopeHash) -> &mut Envelope { - self.collection.entry(*h).or_default() - } pub fn contains_key(&self, h: EnvelopeHash) -> bool { self.collection.contains_key(&h) } @@ -752,33 +757,10 @@ impl Account { } debug!("didn't find {}", h); debug!(&self.folders); - debug!(&self.collection.envelopes); + //debug!(&self.collection.envelopes); unreachable!() } - pub fn thread_to_mail_mut(&mut self, h: ThreadHash, f: FolderHash) -> &mut Envelope { - self.collection - .envelopes - .entry(self.collection.threads[&f].thread_to_mail(h)) - .or_default() - } - pub fn thread_to_mail(&self, h: ThreadHash, f: FolderHash) -> &Envelope { - &self.collection.envelopes[&self.collection.threads[&f].thread_to_mail(h)] - } - pub fn threaded_mail(&self, h: ThreadHash, f: FolderHash) -> EnvelopeHash { - self.collection.threads[&f].thread_to_mail(h) - } - pub fn mail_and_thread( - &mut self, - i: EnvelopeHash, - f: FolderHash, - ) -> (&mut Envelope, &ThreadNode) { - let thread; - { - let x = &mut self.collection.envelopes.entry(i).or_default(); - thread = &self.collection.threads[&f][&x.thread()]; - } - (self.collection.envelopes.entry(i).or_default(), thread) - } + pub fn thread(&self, h: ThreadHash, f: FolderHash) -> &ThreadNode { &self.collection.threads[&f].thread_nodes()[&h] } @@ -836,9 +818,11 @@ impl Account { #[cfg(not(feature = "sqlite3"))] { let mut ret = StackVec::new(); + let envelopes = self.collection.envelopes.clone().read(); + let envelopes = envelopes.unwrap(); for env_hash in self.folders[folder_hash].as_result()?.envelopes { - let envelope = &account.collection[&env_hash]; + let envelope = &envelopes[&env_hash]; if envelope.subject().contains(&search_term) { ret.push(env_hash); continue; diff --git a/ui/src/sqlite3.rs b/ui/src/sqlite3.rs index c96036fc6..adfb49a05 100644 --- a/ui/src/sqlite3.rs +++ b/ui/src/sqlite3.rs @@ -169,17 +169,19 @@ pub fn insert(context: &crate::state::Context) -> Result<()> { .map_err(|e| MeliError::new(e.to_string()))?, ) .map_err(|e| MeliError::new(e.to_string()))?; - for acc in context.accounts.iter() { - debug!("inserting {} envelopes", acc.collection.envelopes.len()); - for e in acc.collection.envelopes.values() { - conn.execute( - "INSERT OR REPLACE INTO envelopes (hash, date, _from, _to, cc, bcc, subject, message_id, in_reply_to, _references, flags, has_attachments, body_text, timestamp) - VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14)", - params![e.hash().to_be_bytes().to_vec(), e.date_as_str(), e.field_from_to_string(), e.field_to_to_string(), e.field_cc_to_string(), e.field_bcc_to_string(), e.subject().into_owned().trim_end_matches('\u{0}'), e.message_id_display().to_string(), e.in_reply_to_display().map(|f| f.to_string()).unwrap_or(String::new()), e.field_references_to_string(), i64::from(e.flags().bits()), if e.has_attachments() { 1 } else { 0 }, String::from("sdfsa"), e.date().to_be_bytes().to_vec()], - ) - .map_err(|e| MeliError::new(e.to_string()))?; + /* + for acc in context.accounts.iter() { + debug!("inserting {} envelopes", acc.collection.envelopes.len()); + for e in acc.collection.envelopes.values() { + conn.execute( + "INSERT OR REPLACE INTO envelopes (hash, date, _from, _to, cc, bcc, subject, message_id, in_reply_to, _references, flags, has_attachments, body_text, timestamp) + VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14)", + params![e.hash().to_be_bytes().to_vec(), e.date_as_str(), e.field_from_to_string(), e.field_to_to_string(), e.field_cc_to_string(), e.field_bcc_to_string(), e.subject().into_owned().trim_end_matches('\u{0}'), e.message_id_display().to_string(), e.in_reply_to_display().map(|f| f.to_string()).unwrap_or(String::new()), e.field_references_to_string(), i64::from(e.flags().bits()), if e.has_attachments() { 1 } else { 0 }, String::from("sdfsa"), e.date().to_be_bytes().to_vec()], + ) + .map_err(|e| MeliError::new(e.to_string()))?; + } } - } + */ Ok(()) }