diff options
author | Matthias Beyer <mail@beyermatthias.de> | 2020-01-03 12:32:56 +0100 |
---|---|---|
committer | Matthias Beyer <mail@beyermatthias.de> | 2020-01-03 16:55:32 +0100 |
commit | 4548ac8f6365e327892e3517ac26ec79aeaa5f68 (patch) | |
tree | f3f79180d5fa3af0a382b445c1e77665d9ff6d60 | |
parent | f79593d9b95172aa9b2039d2a5f1384167b14863 (diff) |
Add Mail::get_thread() for getting all mails in the same thread as this mail
Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
-rw-r--r-- | lib/domain/libimagmail/Cargo.toml | 1 | ||||
-rw-r--r-- | lib/domain/libimagmail/src/lib.rs | 1 | ||||
-rw-r--r-- | lib/domain/libimagmail/src/mail.rs | 65 |
3 files changed, 67 insertions, 0 deletions
diff --git a/lib/domain/libimagmail/Cargo.toml b/lib/domain/libimagmail/Cargo.toml index 1585dd12..e0b1a891 100644 --- a/lib/domain/libimagmail/Cargo.toml +++ b/lib/domain/libimagmail/Cargo.toml @@ -26,6 +26,7 @@ toml-query = "0.9.2" mailparse = "0.8.0" filters = "0.3.0" failure = "0.1.5" +resiter = "0.4.0" serde = "1.0.94" serde_derive = "1.0.94" diff --git a/lib/domain/libimagmail/src/lib.rs b/lib/domain/libimagmail/src/lib.rs index 1a58df0a..3f6ddd3d 100644 --- a/lib/domain/libimagmail/src/lib.rs +++ b/lib/domain/libimagmail/src/lib.rs @@ -43,6 +43,7 @@ extern crate toml; extern crate toml_query; extern crate filters; #[macro_use] extern crate failure; +extern crate resiter; extern crate serde; #[macro_use] extern crate serde_derive; diff --git a/lib/domain/libimagmail/src/mail.rs b/lib/domain/libimagmail/src/mail.rs index b33b4f91..bdcee6a2 100644 --- a/lib/domain/libimagmail/src/mail.rs +++ b/lib/domain/libimagmail/src/mail.rs @@ -21,6 +21,7 @@ use failure::Fallible as Result; use failure::ResultExt; use failure::Error; use toml_query::read::TomlValueReadExt; +use resiter::Filter; use libimagstore::store::Entry; use libimagentryutil::isa::Is; @@ -50,6 +51,7 @@ pub trait Mail : RefFassade + Linkable { fn neighbors(&self) -> Result<StoreIdIterator>; fn get_neighbors<'a>(&self, store: &'a Store) -> Result<MailIterator<'a>>; + fn get_thread<'a>(&self, store: &'a Store) -> Result<MailIterator<'a>>; } @@ -184,6 +186,69 @@ impl Mail for Entry { .into_mail_iterator() }) } + + /// Get the full thread starting from this Mail + /// + /// This function recursively traverses the linked mails, assumes them all to be in the same + /// thread and returns an iterator over all Mails it finds in this way. + /// + /// # Warning + /// + /// If a Mail is linked to this mail (even transitively!) but is _not_ in the same thread, it + /// is considered to be in the same thread. + /// + /// This function works recursively. Keep that in mind for large threads. Because it needs to + /// collect() internally, it might take a lot of memory for large threads. + /// + /// # Return value + /// + /// This function returns an Iterator over StoreIds in the same thread as this mail itself. + /// It does not yield any qualification about the distance between a mail in this thread and + /// this very mail. + /// + fn get_thread<'a>(&self, store: &'a Store) -> Result<MailIterator<'a>> { + trace!("Getting thread, starting point at: {}", self.get_location()); + let mut thread = vec![self.get_location().clone()]; + + fn traverse<'a>(entry: &'a Entry, thread: &mut Vec<StoreId>, store: &Store) -> Result<()> { + // Helper function to get neighbors of a Mail, but filtered + fn get_filtered_neighbors<'a>(entry: &'a Entry, skiplist: &[StoreId]) -> Result<Vec<StoreId>> { + trace!("Getting filtered neighbors of {}", entry.get_location()); + entry.neighbors()?.filter_ok(|id| !skiplist.contains(id)).collect() + } + + // Get the neighbors, filtered by StoreIds which are already in the thread + // Then iterate over them + for n in get_filtered_neighbors(entry, thread)? { + trace!("Fetching {}", n); + + // Get the FileLockEntry for the StoreId, or fail if it cannot be found + let next_entry = store.get(n.clone())?.ok_or_else(|| format_err!("Cannot find {}", n))?; + + // if the FileLockEntry is a Mail + if next_entry.is_mail()? { + trace!("{} is a Mail", n); + thread.push(n); // it belongs to the thread + + // And then traverse further starting from the current Mail + traverse(&next_entry, thread, store)?; + } + } + + Ok(()) + } + + trace!("Starting traversing..."); + traverse(self, &mut thread, store)?; + trace!("Finished traversing."); + trace!("Found {} entries in thread", thread.len()); + + let iter = StoreIdIterator::new(Box::new(thread.into_iter().map(Ok))) + .into_get_iter(store) + .into_mail_iterator(); + + Ok(iter) + } } #[derive(Debug)] |