diff --git a/melib/src/collection.rs b/melib/src/collection.rs index e1a0aee8..1b911257 100644 --- a/melib/src/collection.rs +++ b/melib/src/collection.rs @@ -60,12 +60,19 @@ impl DerefMut for EnvelopeRefMut<'_> { } } -#[derive(Debug, Clone, Default)] +#[derive(Debug, Clone)] pub struct Collection { pub envelopes: Arc>>, - pub threads: HashMap, - sent_mailbox: Option, - pub mailboxes: HashMap>, + pub message_id_index: Arc, EnvelopeHash>>>, + pub threads: Arc>>, + sent_mailbox: Arc>>, + pub mailboxes: Arc>>>, +} + +impl Default for Collection { + fn default() -> Self { + Self::new() + } } /* @@ -89,15 +96,26 @@ impl Drop for Collection { */ impl Collection { - pub fn new(envelopes: HashMap) -> Collection { - let threads = HashMap::with_capacity_and_hasher(16, Default::default()); - let mailboxes = HashMap::with_capacity_and_hasher(16, Default::default()); + pub fn new() -> Collection { + let message_id_index = Arc::new(RwLock::new(HashMap::with_capacity_and_hasher( + 16, + Default::default(), + ))); + let threads = Arc::new(RwLock::new(HashMap::with_capacity_and_hasher( + 16, + Default::default(), + ))); + let mailboxes = Arc::new(RwLock::new(HashMap::with_capacity_and_hasher( + 16, + Default::default(), + ))); Collection { - envelopes: Arc::new(RwLock::new(envelopes)), + envelopes: Arc::new(RwLock::new(Default::default())), + message_id_index, threads, mailboxes, - sent_mailbox: None, + sent_mailbox: Arc::new(RwLock::new(None)), } } @@ -112,14 +130,19 @@ impl Collection { pub fn remove(&mut self, envelope_hash: EnvelopeHash, mailbox_hash: MailboxHash) { debug!("DEBUG: Removing {}", envelope_hash); self.envelopes.write().unwrap().remove(&envelope_hash); - self.mailboxes.entry(mailbox_hash).and_modify(|m| { - m.remove(&envelope_hash); - }); - self.threads + self.mailboxes + .write() + .unwrap() + .entry(mailbox_hash) + .and_modify(|m| { + m.remove(&envelope_hash); + }); + let mut threads_lck = self.threads.write().unwrap(); + threads_lck .entry(mailbox_hash) .or_default() .remove(envelope_hash); - for (h, t) in self.threads.iter_mut() { + for (h, t) in threads_lck.iter_mut() { if *h == mailbox_hash { continue; } @@ -137,15 +160,19 @@ impl Collection { return false; } let mut envelope = self.envelopes.write().unwrap().remove(&old_hash).unwrap(); - self.mailboxes.entry(mailbox_hash).and_modify(|m| { - m.remove(&old_hash); - m.insert(new_hash); - }); + self.mailboxes + .write() + .unwrap() + .entry(mailbox_hash) + .and_modify(|m| { + m.remove(&old_hash); + m.insert(new_hash); + }); envelope.set_hash(new_hash); self.envelopes.write().unwrap().insert(new_hash, envelope); + let mut threads_lck = self.threads.write().unwrap(); { - if self - .threads + if threads_lck .entry(mailbox_hash) .or_default() .update_envelope(&self.envelopes, old_hash, new_hash) @@ -155,11 +182,11 @@ impl Collection { } } /* envelope is not in threads, so insert it */ - self.threads + threads_lck .entry(mailbox_hash) .or_default() .insert(&mut self.envelopes, new_hash); - for (h, t) in self.threads.iter_mut() { + for (h, t) in threads_lck.iter_mut() { if *h == mailbox_hash { continue; } @@ -178,7 +205,7 @@ impl Collection { mailbox_hash: MailboxHash, sent_mailbox: Option, ) -> Option> { - self.sent_mailbox = sent_mailbox; + *self.sent_mailbox.write().unwrap() = sent_mailbox; let &mut Collection { ref mut threads, @@ -188,17 +215,19 @@ impl Collection { .. } = self; - if !threads.contains_key(&mailbox_hash) { - threads.insert(mailbox_hash, Threads::new(new_envelopes.len())); - mailboxes.insert(mailbox_hash, new_envelopes.keys().cloned().collect()); + let mut threads_lck = threads.write().unwrap(); + let mut mailboxes_lck = mailboxes.write().unwrap(); + if !threads_lck.contains_key(&mailbox_hash) { + threads_lck.insert(mailbox_hash, Threads::new(new_envelopes.len())); + mailboxes_lck.insert(mailbox_hash, new_envelopes.keys().cloned().collect()); for (h, e) in new_envelopes { envelopes.write().unwrap().insert(h, e); } } else { - mailboxes.entry(mailbox_hash).and_modify(|m| { + mailboxes_lck.entry(mailbox_hash).and_modify(|m| { m.extend(new_envelopes.keys().cloned()); }); - threads.entry(mailbox_hash).and_modify(|t| { + threads_lck.entry(mailbox_hash).and_modify(|t| { let mut ordered_hash_set = new_envelopes.keys().cloned().collect::>(); ordered_hash_set.sort_by(|a, b| { @@ -218,14 +247,19 @@ impl Collection { } let mut ret = SmallVec::new(); - let keys = threads.keys().cloned().collect::>(); + let keys = threads_lck.keys().cloned().collect::>(); for t_fh in keys { if t_fh == mailbox_hash { continue; } - if sent_mailbox.map(|f| f == mailbox_hash).unwrap_or(false) { + if sent_mailbox + .read() + .unwrap() + .map(|f| f == mailbox_hash) + .unwrap_or(false) + { let envelopes_lck = envelopes.read().unwrap(); - let mut ordered_hash_set = threads[&mailbox_hash] + let mut ordered_hash_set = threads_lck[&mailbox_hash] .hash_set .iter() .cloned() @@ -239,16 +273,24 @@ impl Collection { drop(envelopes_lck); let mut updated = false; for h in ordered_hash_set { - updated |= threads.entry(t_fh).or_default().insert_reply(envelopes, h); + updated |= threads_lck + .entry(t_fh) + .or_default() + .insert_reply(envelopes, h); } if updated { ret.push(t_fh); } continue; } - if sent_mailbox.map(|f| f == t_fh).unwrap_or(false) { + if sent_mailbox + .read() + .unwrap() + .map(|f| f == t_fh) + .unwrap_or(false) + { let envelopes_lck = envelopes.read().unwrap(); - let mut ordered_hash_set = threads[&t_fh] + let mut ordered_hash_set = threads_lck[&t_fh] .hash_set .iter() .cloned() @@ -262,7 +304,7 @@ impl Collection { drop(envelopes_lck); let mut updated = false; for h in ordered_hash_set { - updated |= threads + updated |= threads_lck .entry(mailbox_hash) .or_default() .insert_reply(envelopes, h); @@ -288,24 +330,30 @@ impl Collection { let old_env = self.envelopes.write().unwrap().remove(&old_hash).unwrap(); envelope.set_thread(old_env.thread()); let new_hash = envelope.hash(); - self.mailboxes.entry(mailbox_hash).and_modify(|m| { - m.remove(&old_hash); - m.insert(new_hash); - }); + self.mailboxes + .write() + .unwrap() + .entry(mailbox_hash) + .and_modify(|m| { + m.remove(&old_hash); + m.insert(new_hash); + }); self.envelopes.write().unwrap().insert(new_hash, envelope); + let mut threads_lck = self.threads.write().unwrap(); if self .sent_mailbox + .read() + .unwrap() .map(|f| f == mailbox_hash) .unwrap_or(false) { - for (_, t) in self.threads.iter_mut() { + for (_, t) in threads_lck.iter_mut() { t.update_envelope(&self.envelopes, old_hash, new_hash) .unwrap_or(()); } } { - if self - .threads + if threads_lck .entry(mailbox_hash) .or_default() .update_envelope(&self.envelopes, old_hash, new_hash) @@ -315,11 +363,11 @@ impl Collection { } } /* envelope is not in threads, so insert it */ - self.threads + threads_lck .entry(mailbox_hash) .or_default() .insert(&mut self.envelopes, new_hash); - for (h, t) in self.threads.iter_mut() { + for (h, t) in threads_lck.iter_mut() { if *h == mailbox_hash { continue; } @@ -330,19 +378,21 @@ impl Collection { } pub fn update_flags(&mut self, env_hash: EnvelopeHash, mailbox_hash: MailboxHash) { + let mut threads_lck = self.threads.write().unwrap(); if self .sent_mailbox + .read() + .unwrap() .map(|f| f == mailbox_hash) .unwrap_or(false) { - for (_, t) in self.threads.iter_mut() { + for (_, t) in threads_lck.iter_mut() { t.update_envelope(&self.envelopes, env_hash, env_hash) .unwrap_or(()); } } { - if self - .threads + if threads_lck .entry(mailbox_hash) .or_default() .update_envelope(&self.envelopes, env_hash, env_hash) @@ -352,11 +402,11 @@ impl Collection { } } /* envelope is not in threads, so insert it */ - self.threads + threads_lck .entry(mailbox_hash) .or_default() .insert(&mut self.envelopes, env_hash); - for (h, t) in self.threads.iter_mut() { + for (h, t) in threads_lck.iter_mut() { if *h == mailbox_hash { continue; } @@ -368,16 +418,24 @@ impl Collection { pub fn insert(&mut self, envelope: Envelope, mailbox_hash: MailboxHash) -> bool { let hash = envelope.hash(); - self.mailboxes.entry(mailbox_hash).and_modify(|m| { - m.insert(hash); - }); + self.mailboxes + .write() + .unwrap() + .entry(mailbox_hash) + .and_modify(|m| { + m.insert(hash); + }); self.envelopes.write().unwrap().insert(hash, envelope); self.threads + .write() + .unwrap() .entry(mailbox_hash) .or_default() .insert(&mut self.envelopes, hash); if self .sent_mailbox + .read() + .unwrap() .map(|f| f == mailbox_hash) .unwrap_or(false) { @@ -388,7 +446,7 @@ impl Collection { pub fn insert_reply(&mut self, env_hash: EnvelopeHash) { debug_assert!(self.envelopes.read().unwrap().contains_key(&env_hash)); - for (_, t) in self.threads.iter_mut() { + for (_, t) in self.threads.write().unwrap().iter_mut() { t.insert_reply(&mut self.envelopes, env_hash); } } @@ -403,27 +461,45 @@ impl Collection { EnvelopeRefMut { guard, env_hash } } + pub fn get_threads(&'_ self, hash: MailboxHash) -> RwRef<'_, MailboxHash, Threads> { + let guard = self.threads.read().unwrap(); + RwRef { guard, hash } + } + + pub fn get_mailbox( + &'_ self, + hash: MailboxHash, + ) -> RwRef<'_, MailboxHash, HashSet> { + let guard = self.mailboxes.read().unwrap(); + RwRef { guard, hash } + } + pub fn contains_key(&self, env_hash: &EnvelopeHash) -> bool { self.envelopes.read().unwrap().contains_key(env_hash) } pub fn new_mailbox(&mut self, mailbox_hash: MailboxHash) { - if !self.mailboxes.contains_key(&mailbox_hash) { - self.mailboxes.insert(mailbox_hash, Default::default()); - self.threads.insert(mailbox_hash, Threads::default()); + let mut mailboxes_lck = self.mailboxes.write().unwrap(); + if !mailboxes_lck.contains_key(&mailbox_hash) { + mailboxes_lck.insert(mailbox_hash, Default::default()); + self.threads + .write() + .unwrap() + .insert(mailbox_hash, Threads::default()); } } } -impl Index<&MailboxHash> for Collection { - type Output = HashSet; - fn index(&self, index: &MailboxHash) -> &HashSet { - &self.mailboxes[index] - } + +pub struct RwRef<'g, K: std::cmp::Eq + std::hash::Hash, V> { + guard: RwLockReadGuard<'g, HashMap>, + hash: K, } -impl IndexMut<&MailboxHash> for Collection { - fn index_mut(&mut self, index: &MailboxHash) -> &mut HashSet { - self.mailboxes.get_mut(index).unwrap() +impl Deref for RwRef<'_, K, V> { + type Target = V; + + fn deref(&self) -> &V { + self.guard.get(&self.hash).unwrap() } } diff --git a/src/components/mail/listing.rs b/src/components/mail/listing.rs index 68403469..b70b5c8c 100644 --- a/src/components/mail/listing.rs +++ b/src/components/mail/listing.rs @@ -148,9 +148,13 @@ pub trait MailListingTrait: ListingTrait { let account = &mut context.accounts[account_pos]; let mut envs_to_set: SmallVec<[EnvelopeHash; 8]> = SmallVec::new(); let mailbox_hash = self.coordinates().1; - for (_, h) in account.collection.threads[&mailbox_hash].thread_group_iter(thread_hash) { + for (_, h) in account + .collection + .get_threads(mailbox_hash) + .thread_group_iter(thread_hash) + { envs_to_set.push( - account.collection.threads[&mailbox_hash].thread_nodes()[&h] + account.collection.get_threads(mailbox_hash).thread_nodes()[&h] .message() .unwrap(), ); @@ -1209,7 +1213,7 @@ impl Component for Listing { MailboxStatus::Available | MailboxStatus::Parsing(_, _) => format!( "Mailbox: {}, Messages: {}, New: {}", account[&mailbox_hash].ref_mailbox.name(), - account.collection[&mailbox_hash].len(), + account.collection.get_mailbox(mailbox_hash).len(), account[&mailbox_hash] .ref_mailbox .count() diff --git a/src/components/mail/listing/compact.rs b/src/components/mail/listing/compact.rs index 8ab339a1..e34a8196 100644 --- a/src/components/mail/listing/compact.rs +++ b/src/components/mail/listing/compact.rs @@ -247,7 +247,9 @@ impl MailListingTrait for CompactListing { } } - let threads = &context.accounts[self.cursor_pos.0].collection.threads[&self.cursor_pos.1]; + let threads = context.accounts[self.cursor_pos.0] + .collection + .get_threads(self.cursor_pos.1); let mut roots = threads.roots(); threads.group_inner_sort_by( &mut roots, @@ -276,7 +278,7 @@ impl MailListingTrait for CompactListing { ) { let account = &context.accounts[self.cursor_pos.0]; - let threads = &account.collection.threads[&self.cursor_pos.1]; + let threads = account.collection.get_threads(self.cursor_pos.1); self.order.clear(); self.length = 0; let mut rows = Vec::with_capacity(1024); @@ -341,7 +343,7 @@ impl MailListingTrait for CompactListing { } } - let entry_strings = self.make_entry_string(&root_envelope, context, threads, thread); + let entry_strings = self.make_entry_string(&root_envelope, context, &threads, thread); row_widths.1.push( entry_strings .date @@ -462,7 +464,7 @@ impl ListingTrait for CompactListing { let thread_hash = self.get_thread_under_cursor(idx); let account = &context.accounts[self.cursor_pos.0]; - let threads = &account.collection.threads[&self.cursor_pos.1]; + let threads = account.collection.get_threads(self.cursor_pos.1); let thread = threads.thread_ref(thread_hash); let row_attr = row_attr!( @@ -685,7 +687,7 @@ impl ListingTrait for CompactListing { } let account = &context.accounts[self.cursor_pos.0]; - let threads = &account.collection.threads[&self.cursor_pos.1]; + let threads = account.collection.get_threads(self.cursor_pos.1); for r in 0..cmp::min(self.length - top_idx, rows) { let thread_hash = self.get_thread_under_cursor(r + top_idx); let row_attr = row_attr!( @@ -767,7 +769,7 @@ impl ListingTrait for CompactListing { let account = &context.accounts[self.cursor_pos.0]; match results { Ok(results) => { - let threads = &account.collection.threads[&self.cursor_pos.1]; + let threads = account.collection.get_threads(self.cursor_pos.1); for env_hash in results { if !account.collection.contains_key(&env_hash) { continue; @@ -971,7 +973,7 @@ impl CompactListing { fn update_line(&mut self, context: &Context, thread_hash: ThreadHash) { let account = &context.accounts[self.cursor_pos.0]; - let threads = &account.collection.threads[&self.cursor_pos.1]; + let threads = account.collection.get_threads(self.cursor_pos.1); let thread = threads.thread_ref(thread_hash); let thread_node_hash = threads.thread_group_iter(thread_hash).next().unwrap().1; if let Some(env_hash) = threads.thread_nodes()[&thread_node_hash].message() { @@ -993,7 +995,7 @@ impl CompactListing { self.color_cache.odd }; let envelope: EnvelopeRef = account.collection.get_env(env_hash); - let strings = self.make_entry_string(&envelope, context, threads, thread_hash); + let strings = self.make_entry_string(&envelope, context, &threads, thread_hash); drop(envelope); let columns = &mut self.data_columns.columns; let min_width = ( @@ -1136,7 +1138,7 @@ impl CompactListing { ); let account = &context.accounts[self.cursor_pos.0]; - let threads = &account.collection.threads[&self.cursor_pos.1]; + let threads = account.collection.get_threads(self.cursor_pos.1); for ((idx, (thread_hash, root_env_hash)), strings) in self.rows.iter().skip(start).take(end - start + 1) @@ -1309,7 +1311,7 @@ impl CompactListing { let account = &context.accounts[self.cursor_pos.0]; match results { Ok(results) => { - let threads = &account.collection.threads[&self.cursor_pos.1]; + let threads = account.collection.get_threads(self.cursor_pos.1); for env_hash in results { if !account.collection.contains_key(&env_hash) { continue; @@ -1497,6 +1499,8 @@ impl Component for CompactListing { account .collection .threads + .write() + .unwrap() .entry(self.cursor_pos.1) .and_modify(|threads| { let is_snoozed = threads.thread_ref(thread).snoozed(); @@ -1526,7 +1530,7 @@ impl Component for CompactListing { } UIEvent::EnvelopeRename(ref old_hash, ref new_hash) => { let account = &context.accounts[self.cursor_pos.0]; - let threads = &account.collection.threads[&self.cursor_pos.1]; + let threads = account.collection.get_threads(self.cursor_pos.1); if !account.collection.contains_key(&new_hash) { return false; } @@ -1536,6 +1540,7 @@ impl Component for CompactListing { } let thread: ThreadHash = threads.find_group(threads.thread_nodes()[&new_env_thread_node_hash].group); + drop(threads); if self.order.contains_key(&thread) { self.row_updates.push(thread); } @@ -1553,7 +1558,7 @@ impl Component for CompactListing { } UIEvent::EnvelopeUpdate(ref env_hash) => { let account = &context.accounts[self.cursor_pos.0]; - let threads = &account.collection.threads[&self.cursor_pos.1]; + let threads = account.collection.get_threads(self.cursor_pos.1); if !account.collection.contains_key(&env_hash) { return false; } @@ -1563,6 +1568,7 @@ impl Component for CompactListing { } let thread: ThreadHash = threads.find_group(threads.thread_nodes()[&new_env_thread_node_hash].group); + drop(threads); if self.order.contains_key(&thread) { self.row_updates.push(thread); } diff --git a/src/components/mail/listing/conversations.rs b/src/components/mail/listing/conversations.rs index cb69bd10..3ea5c1de 100644 --- a/src/components/mail/listing/conversations.rs +++ b/src/components/mail/listing/conversations.rs @@ -152,7 +152,9 @@ impl MailListingTrait for ConversationsListing { } } - let threads = &context.accounts[self.cursor_pos.0].collection.threads[&self.cursor_pos.1]; + let threads = context.accounts[self.cursor_pos.0] + .collection + .get_threads(self.cursor_pos.1); self.all_threads.clear(); let mut roots = threads.roots(); threads.group_inner_sort_by( @@ -183,7 +185,7 @@ impl MailListingTrait for ConversationsListing { ) { let account = &context.accounts[self.cursor_pos.0]; - let threads = &account.collection.threads[&self.cursor_pos.1]; + let threads = account.collection.get_threads(self.cursor_pos.1); self.order.clear(); self.selection.clear(); self.length = 0; @@ -255,8 +257,13 @@ impl MailListingTrait for ConversationsListing { } } - let strings = - self.make_entry_string(root_envelope, context, &from_address_list, threads, thread); + let strings = self.make_entry_string( + root_envelope, + context, + &from_address_list, + &threads, + thread, + ); max_entry_columns = std::cmp::max( max_entry_columns, strings.flag.len() @@ -436,7 +443,7 @@ impl ListingTrait for ConversationsListing { let thread_hash = self.get_thread_under_cursor(idx); let account = &context.accounts[self.cursor_pos.0]; - let threads = &account.collection.threads[&self.cursor_pos.1]; + let threads = account.collection.get_threads(self.cursor_pos.1); let thread = threads.thread_ref(thread_hash); let fg_color = if thread.unseen() > 0 { @@ -717,7 +724,7 @@ impl ListingTrait for ConversationsListing { let account = &context.accounts[self.cursor_pos.0]; match results { Ok(results) => { - let threads = &account.collection.threads[&self.cursor_pos.1]; + let threads = account.collection.get_threads(self.cursor_pos.1); for env_hash in results { if !account.collection.contains_key(&env_hash) { continue; @@ -952,7 +959,7 @@ impl ConversationsListing { fn update_line(&mut self, context: &Context, thread_hash: ThreadHash) { let account = &context.accounts[self.cursor_pos.0]; - let threads = &account.collection.threads[&self.cursor_pos.1]; + let threads = account.collection.get_threads(self.cursor_pos.1); let thread = threads.thread_ref(thread_hash); let thread_node_hash = threads.thread_group_iter(thread_hash).next().unwrap().1; let idx: usize = self.order[&thread_hash]; @@ -989,8 +996,13 @@ impl ConversationsListing { } } let envelope: EnvelopeRef = account.collection.get_env(env_hash); - let strings = - self.make_entry_string(&envelope, context, &from_address_list, threads, thread_hash); + let strings = self.make_entry_string( + &envelope, + context, + &from_address_list, + &threads, + thread_hash, + ); drop(envelope); /* draw flags */ let (x, _) = write_string_to_grid( @@ -1236,7 +1248,7 @@ impl Component for ConversationsListing { } UIEvent::EnvelopeRename(ref old_hash, ref new_hash) => { let account = &context.accounts[self.cursor_pos.0]; - let threads = &account.collection.threads[&self.cursor_pos.1]; + let threads = account.collection.get_threads(self.cursor_pos.1); if !account.collection.contains_key(&new_hash) { return false; } @@ -1246,6 +1258,7 @@ impl Component for ConversationsListing { } let thread: ThreadHash = threads.find_group(threads.thread_nodes()[&env_thread_node_hash].group); + drop(threads); if self.order.contains_key(&thread) { self.row_updates.push(thread); } @@ -1257,7 +1270,7 @@ impl Component for ConversationsListing { } UIEvent::EnvelopeUpdate(ref env_hash) => { let account = &context.accounts[self.cursor_pos.0]; - let threads = &account.collection.threads[&self.cursor_pos.1]; + let threads = account.collection.get_threads(self.cursor_pos.1); if !account.collection.contains_key(&env_hash) { return false; } @@ -1267,6 +1280,7 @@ impl Component for ConversationsListing { } let thread: ThreadHash = threads.find_group(threads.thread_nodes()[&env_thread_node_hash].group); + drop(threads); if self.order.contains_key(&thread) { self.row_updates.push(thread); } @@ -1315,6 +1329,8 @@ impl Component for ConversationsListing { account .collection .threads + .write() + .unwrap() .entry(self.cursor_pos.1) .and_modify(|threads| { let is_snoozed = threads.thread_ref(thread).snoozed(); diff --git a/src/components/mail/listing/plain.rs b/src/components/mail/listing/plain.rs index 20b324e4..21d16f8f 100644 --- a/src/components/mail/listing/plain.rs +++ b/src/components/mail/listing/plain.rs @@ -169,7 +169,9 @@ impl MailListingTrait for PlainListing { return; } } - self.local_collection = context.accounts[self.cursor_pos.0].collection[&self.cursor_pos.1] + self.local_collection = context.accounts[self.cursor_pos.0] + .collection + .get_mailbox(self.cursor_pos.1) .iter() .cloned() .collect(); @@ -178,8 +180,9 @@ impl MailListingTrait for PlainListing { .envelopes .read() .unwrap(); - self.thread_node_hashes = context.accounts[self.cursor_pos.0].collection - [&self.cursor_pos.1] + self.thread_node_hashes = context.accounts[self.cursor_pos.0] + .collection + .get_mailbox(self.cursor_pos.1) .iter() .map(|h| (*h, env_lck[h].thread())) .collect(); @@ -232,7 +235,7 @@ impl MailListingTrait for PlainListing { items: Box>, ) { let account = &context.accounts[self.cursor_pos.0]; - let threads = &account.collection.threads[&self.cursor_pos.1]; + let threads = account.collection.get_threads(self.cursor_pos.1); let roots = items .filter_map(|r| threads.groups[&r].root().map(|r| r.root)) .collect::<_>(); @@ -1218,7 +1221,10 @@ impl Component for PlainListing { UIEvent::EnvelopeRename(ref old_hash, ref new_hash) => { let account = &context.accounts[self.cursor_pos.0]; if !account.collection.contains_key(new_hash) - || !account.collection[&self.cursor_pos.1].contains(new_hash) + || !account + .collection + .get_mailbox(self.cursor_pos.1) + .contains(new_hash) { return false; } @@ -1244,7 +1250,10 @@ impl Component for PlainListing { UIEvent::EnvelopeUpdate(ref env_hash) => { let account = &context.accounts[self.cursor_pos.0]; if !account.collection.contains_key(env_hash) - || !account.collection[&self.cursor_pos.1].contains(env_hash) + || !account + .collection + .get_mailbox(self.cursor_pos.1) + .contains(env_hash) { return false; } diff --git a/src/components/mail/listing/thread.rs b/src/components/mail/listing/thread.rs index 0421f5fb..10f7df66 100644 --- a/src/components/mail/listing/thread.rs +++ b/src/components/mail/listing/thread.rs @@ -121,7 +121,9 @@ impl MailListingTrait for ThreadListing { return; } } - let threads = &context.accounts[self.cursor_pos.0].collection.threads[&self.cursor_pos.1]; + let threads = context.accounts[self.cursor_pos.0] + .collection + .get_threads(self.cursor_pos.1); let mut roots = threads.roots(); threads.group_inner_sort_by( &mut roots, @@ -141,7 +143,7 @@ impl MailListingTrait for ThreadListing { items: Box>, ) { let account = &context.accounts[self.cursor_pos.0]; - let threads = &account.collection.threads[&self.cursor_pos.1]; + let threads = account.collection.get_threads(self.cursor_pos.1); self.length = 0; self.order.clear(); let default_cell = { @@ -226,7 +228,7 @@ impl MailListingTrait for ThreadListing { idx, indentation, thread_node_hash, - threads, + &threads, &indentations, has_sibling, is_root, @@ -1164,7 +1166,6 @@ impl Component for ThreadListing { } UIEvent::EnvelopeRename(ref old_hash, ref new_hash) => { let account = &context.accounts[self.cursor_pos.0]; - let threads = &account.collection.threads[&self.cursor_pos.1]; if !account.collection.contains_key(&new_hash) { return false; } @@ -1188,7 +1189,6 @@ impl Component for ThreadListing { } UIEvent::EnvelopeUpdate(ref env_hash) => { let account = &context.accounts[self.cursor_pos.0]; - let threads = &account.collection.threads[&self.cursor_pos.1]; if !account.collection.contains_key(env_hash) { return false; } diff --git a/src/components/mail/view/thread.rs b/src/components/mail/view/thread.rs index 3a0a5c71..3a875731 100644 --- a/src/components/mail/view/thread.rs +++ b/src/components/mail/view/thread.rs @@ -161,7 +161,7 @@ impl ThreadView { fn initiate(&mut self, expanded_hash: Option, context: &Context) { let account = &context.accounts[self.coordinates.0]; - let threads = &account.collection.threads[&self.coordinates.1]; + let threads = account.collection.get_threads(self.coordinates.1); if !threads.groups.contains_key(&self.thread_group) { return; @@ -648,7 +648,7 @@ impl ThreadView { let y = if self.dirty { clear_area(grid, area, crate::conf::value(context, "theme_default")); let account = &context.accounts[self.coordinates.0]; - let threads = &account.collection.threads[&self.coordinates.1]; + let threads = account.collection.get_threads(self.coordinates.1); let thread_root = threads .thread_group_iter(self.thread_group) .next() @@ -751,7 +751,7 @@ impl ThreadView { let y = { clear_area(grid, area, crate::conf::value(context, "theme_default")); let account = &context.accounts[self.coordinates.0]; - let threads = &account.collection.threads[&self.coordinates.1]; + let threads = account.collection.get_threads(self.coordinates.1); let thread_root = threads .thread_group_iter(self.thread_group) .next() diff --git a/src/conf/accounts.rs b/src/conf/accounts.rs index 0984060f..c6572417 100644 --- a/src/conf/accounts.rs +++ b/src/conf/accounts.rs @@ -726,7 +726,10 @@ impl Account { RefreshEventKind::Create(envelope) => { let env_hash = envelope.hash(); if self.collection.contains_key(&env_hash) - && self.collection[&mailbox_hash].contains(&env_hash) + && self + .collection + .get_mailbox(mailbox_hash) + .contains(&env_hash) { return None; } @@ -770,10 +773,13 @@ impl Account { let thread = { let thread_hash = self.collection.get_env(env_hash).thread(); - self.collection.threads[&mailbox_hash] - .find_group(self.collection.threads[&mailbox_hash][&thread_hash].group) + self.collection.get_threads(mailbox_hash).find_group( + self.collection.get_threads(mailbox_hash)[&thread_hash].group, + ) }; - if self.collection.threads[&mailbox_hash] + if self + .collection + .get_threads(mailbox_hash) .thread_ref(thread) .snoozed() { @@ -797,8 +803,9 @@ impl Account { RefreshEventKind::Remove(env_hash) => { let thread_hash = { let thread_hash = self.collection.get_env(env_hash).thread(); - self.collection.threads[&mailbox_hash] - .find_group(self.collection.threads[&mailbox_hash][&thread_hash].group) + self.collection.get_threads(mailbox_hash).find_group( + self.collection.get_threads(mailbox_hash)[&thread_hash].group, + ) }; #[cfg(feature = "sqlite3")] { @@ -1006,7 +1013,12 @@ impl Account { None => { return match self.mailbox_entries[&mailbox_hash].status { MailboxStatus::Available | MailboxStatus::Parsing(_, _) - if self.collection.mailboxes.contains_key(&mailbox_hash) => + if self + .collection + .mailboxes + .read() + .unwrap() + .contains_key(&mailbox_hash) => { Ok(()) } @@ -1157,7 +1169,12 @@ impl Account { } if self.mailbox_entries[&mailbox_hash].status.is_available() || (self.mailbox_entries[&mailbox_hash].status.is_parsing() - && self.collection.mailboxes.contains_key(&mailbox_hash)) + && self + .collection + .mailboxes + .read() + .unwrap() + .contains_key(&mailbox_hash)) { Ok(()) } else { @@ -1346,10 +1363,6 @@ impl Account { }) } - pub fn thread(&self, h: ThreadNodeHash, f: MailboxHash) -> &ThreadNode { - &self.collection.threads[&f].thread_nodes()[&h] - } - pub fn mailbox_operation( &mut self, op: crate::execute::actions::MailboxOperation, @@ -1417,9 +1430,13 @@ impl Account { ); self.collection .threads + .write() + .unwrap() .insert(mailbox_hash, Threads::default()); self.collection .mailboxes + .write() + .unwrap() .insert(mailbox_hash, Default::default()); build_mailboxes_order( &mut self.tree, @@ -1451,7 +1468,11 @@ impl Account { if self.sent_mailbox == Some(mailbox_hash) { self.sent_mailbox = None; } - self.collection.threads.remove(&mailbox_hash); + self.collection + .threads + .write() + .unwrap() + .remove(&mailbox_hash); let deleted_mailbox = self.mailbox_entries.remove(&mailbox_hash).unwrap(); /* if deleted mailbox had parent, we need to update its children field */ if let Some(parent_hash) = deleted_mailbox.ref_mailbox.parent() { @@ -1461,7 +1482,11 @@ impl Account { parent.ref_mailbox = mailboxes.remove(&parent_hash).unwrap(); }); } - self.collection.mailboxes.remove(&mailbox_hash); + self.collection + .mailboxes + .write() + .unwrap() + .remove(&mailbox_hash); build_mailboxes_order( &mut self.tree, &self.mailbox_entries, @@ -1576,7 +1601,7 @@ impl Account { let mut ret = SmallVec::new(); let envelopes = self.collection.envelopes.read().unwrap(); - for &env_hash in self.collection[&mailbox_hash].iter() { + for &env_hash in self.collection.get_mailbox(mailbox_hash).iter() { let envelope = &envelopes[&env_hash]; if envelope.subject().contains(&search_term) { ret.push(env_hash);