From 4806f7ff84c595ec6647744577388fe4fab33736 Mon Sep 17 00:00:00 2001 From: Quentin Dufour Date: Fri, 5 Jan 2024 18:59:19 +0100 Subject: WIP rewrite with a query manager --- src/mail/mailbox.rs | 2 +- src/mail/query.rs | 114 ++++++++++++++++++++++++++++++++++++++++----------- src/mail/snapshot.rs | 10 +++++ 3 files changed, 100 insertions(+), 26 deletions(-) (limited to 'src/mail') diff --git a/src/mail/mailbox.rs b/src/mail/mailbox.rs index 306fd7d..2a0a24a 100644 --- a/src/mail/mailbox.rs +++ b/src/mail/mailbox.rs @@ -82,7 +82,7 @@ impl Mailbox { self.mbox.read().await.fetch_full(id, message_key).await } - async fn frozen(self: &std::sync::Arc) -> super::snapshot::FrozenMailbox { + pub async fn frozen(self: &std::sync::Arc) -> super::snapshot::FrozenMailbox { super::snapshot::FrozenMailbox::new(self.clone()).await } diff --git a/src/mail/query.rs b/src/mail/query.rs index 631ad56..5beff37 100644 --- a/src/mail/query.rs +++ b/src/mail/query.rs @@ -10,10 +10,27 @@ use futures::stream::{FuturesUnordered, StreamExt}; pub struct Query<'a,'b> { pub frozen: &'a FrozenMailbox, pub emails: &'b [UniqueIdent], + pub scope: QueryScope, +} + +pub enum QueryScope { + Index, + Partial, + Full, } impl<'a,'b> Query<'a,'b> { - pub fn index(&self) -> Result> { + pub async fn fetch(&self) -> Result> { + match self.scope { + QueryScope::Index => self.index(), + QueryScope::Partial => self.partial().await, + QueryScope::Full => self.full().await, + } + } + + // --- functions below are private *for reasons* + + fn index(&self) -> Result> { self .emails .iter() @@ -23,18 +40,18 @@ impl<'a,'b> Query<'a,'b> { .snapshot .table .get(uuid) - .map(|index| IndexResult { uuid: *uuid, index }) + .map(|index| QueryResult::IndexResult { uuid: *uuid, index }) .ok_or(anyhow!("missing email in index")) }) .collect::, _>>() } - pub async fn partial(&self) -> Result> { + async fn partial(&self) -> Result> { let meta = self.frozen.mailbox.fetch_meta(self.emails).await?; let result = meta .into_iter() .zip(self.index()?) - .map(|(metadata, index)| PartialResult { uuid: index.uuid, index: index.index, metadata }) + .map(|(metadata, index)| index.into_partial(metadata).expect("index to be IndexResult")) .collect::>(); Ok(result) } @@ -43,18 +60,17 @@ impl<'a,'b> Query<'a,'b> { /// AND GENERATE SO MUCH NETWORK TRAFFIC. /// THIS FUNCTION SHOULD BE REWRITTEN, FOR EXAMPLE WITH /// SOMETHING LIKE AN ITERATOR - pub async fn full(&self) -> Result> { + async fn full(&self) -> Result> { let meta_list = self.partial().await?; meta_list .into_iter() .map(|meta| async move { - let content = self.frozen.mailbox.fetch_full(meta.uuid, &meta.metadata.message_key).await?; - Ok(FullResult { - uuid: meta.uuid, - index: meta.index, - metadata: meta.metadata, - content, - }) + let content = self.frozen.mailbox.fetch_full( + *meta.uuid(), + &meta.metadata().expect("meta to be PartialResult").message_key + ).await?; + + Ok(meta.into_full(content).expect("meta to be PartialResult")) }) .collect::>() .collect::>() @@ -64,18 +80,66 @@ impl<'a,'b> Query<'a,'b> { } } -pub struct IndexResult<'a> { - pub uuid: UniqueIdent, - pub index: &'a IndexEntry, -} -pub struct PartialResult<'a> { - pub uuid: UniqueIdent, - pub index: &'a IndexEntry, - pub metadata: MailMeta, +pub enum QueryResult<'a> { + IndexResult { + uuid: UniqueIdent, + index: &'a IndexEntry, + }, + PartialResult { + uuid: UniqueIdent, + index: &'a IndexEntry, + metadata: MailMeta, + }, + FullResult { + uuid: UniqueIdent, + index: &'a IndexEntry, + metadata: MailMeta, + content: Vec, + } } -pub struct FullResult<'a> { - pub uuid: UniqueIdent, - pub index: &'a IndexEntry, - pub metadata: MailMeta, - pub content: Vec, +impl<'a> QueryResult<'a> { + pub fn uuid(&self) -> &UniqueIdent { + match self { + Self::IndexResult { uuid, .. } => uuid, + Self::PartialResult { uuid, .. } => uuid, + Self::FullResult { uuid, .. } => uuid, + } + } + + pub fn index(&self) -> &IndexEntry { + match self { + Self::IndexResult { index, .. } => index, + Self::PartialResult { index, .. } => index, + Self::FullResult { index, .. } => index, + } + } + + pub fn metadata(&self) -> Option<&MailMeta> { + match self { + Self::IndexResult { .. } => None, + Self::PartialResult { metadata, .. } => Some(metadata), + Self::FullResult { metadata, .. } => Some(metadata), + } + } + + pub fn content(&self) -> Option<&[u8]> { + match self { + Self::FullResult { content, .. } => Some(content), + _ => None, + } + } + + fn into_partial(self, metadata: MailMeta) -> Option { + match self { + Self::IndexResult { uuid, index } => Some(Self::PartialResult { uuid, index, metadata }), + _ => None, + } + } + + fn into_full(self, content: Vec) -> Option { + match self { + Self::PartialResult { uuid, index, metadata } => Some(Self::FullResult { uuid, index, metadata, content }), + _ => None, + } + } } diff --git a/src/mail/snapshot.rs b/src/mail/snapshot.rs index 54bec64..c3145b4 100644 --- a/src/mail/snapshot.rs +++ b/src/mail/snapshot.rs @@ -4,6 +4,8 @@ use anyhow::Result; use super::mailbox::Mailbox; use super::uidindex::UidIndex; +use super::unique_ident::UniqueIdent; +use super::query::{Query, QueryScope}; /// A Frozen Mailbox has a snapshot of the current mailbox /// state that is desynchronized with the real mailbox state. @@ -49,4 +51,12 @@ impl FrozenMailbox { old_snapshot } + + pub fn query<'a, 'b>(&'a self, uuids: &'b [UniqueIdent], scope: QueryScope) -> Query<'a, 'b> { + Query { + frozen: self, + emails: uuids, + scope, + } + } } -- cgit v1.2.3