email/backend/
mod.rs

1//! # Backend
2//!
3//! A backend is a set of features like adding folder, listing
4//! envelopes or sending message. This module exposes everything you
5//! need to create your own backend.
6//!
7//! ## Dynamic backend
8//!
9//! A dynamic backend is composed of features defined at
10//! runtime. Calling an undefined feature leads to a runtime
11//! error. Such backend is useful when you do not know in advance
12//! which feature is enabled or disabled (for example, from a user
13//! configuration file).
14//!
15//! The simplest way to build a dynamic backend is to use the
16//! [`BackendBuilder`]. It allows you to dynamically enable or disable
17//! features using the builder pattern. The `build` method consumes
18//! the builder to build the final backend. This module comes with two
19//! backend implementations:
20//!
21//! - [`Backend`], a basic backend instance exposing features directly
22//!
23//! - [`BackendPool`], a backend where multiple contexts are
24//! built and put in a pool, which allow you to execute features in
25//! parallel
26//!
27//! You can create your own instance by implementing the
28//! [`AsyncTryIntoBackendFeatures`] trait.
29//!
30//! See a full example at `../../tests/dynamic_backend.rs`.
31//!
32//! ## Static backend
33//!
34//! A static backend is composed of features defined at compilation
35//! time. Such backend is useful when you know in advance which
36//! feature should be enabled or disabled. It mostly relies on
37//! traits. You will have to create your own backend instance as well
38//! as manually implement backend features.
39//!
40//! See a full example at `../../tests/static_backend.rs`.
41
42pub mod context;
43mod error;
44pub mod feature;
45pub mod mapper;
46pub mod macros {
47    pub use email_macros::BackendContext;
48}
49
50#[cfg(feature = "sync")]
51use std::hash::DefaultHasher;
52use std::sync::Arc;
53
54use async_trait::async_trait;
55use paste::paste;
56#[cfg(feature = "watch")]
57use tokio::sync::oneshot::{Receiver, Sender};
58
59#[doc(inline)]
60pub use self::error::{Error, Result};
61use self::{
62    context::{BackendContext, BackendContextBuilder},
63    feature::{BackendFeature, BackendFeatureSource, CheckUp},
64};
65#[cfg(feature = "watch")]
66use crate::envelope::watch::WatchEnvelopes;
67#[cfg(feature = "thread")]
68use crate::envelope::{thread::ThreadEnvelopes, ThreadedEnvelopes};
69#[cfg(feature = "sync")]
70use crate::sync::hash::SyncHash;
71use crate::{
72    account::config::{AccountConfig, HasAccountConfig},
73    envelope::{
74        get::GetEnvelope,
75        list::{ListEnvelopes, ListEnvelopesOptions},
76        Envelope, Envelopes, Id, SingleId,
77    },
78    flag::{add::AddFlags, remove::RemoveFlags, set::SetFlags, Flags},
79    folder::{
80        add::AddFolder, delete::DeleteFolder, expunge::ExpungeFolder, list::ListFolders,
81        purge::PurgeFolder, Folders,
82    },
83    message::{
84        add::AddMessage, copy::CopyMessages, delete::DeleteMessages, get::GetMessages,
85        peek::PeekMessages, r#move::MoveMessages, remove::RemoveMessages, send::SendMessage,
86        Messages,
87    },
88    AnyResult,
89};
90
91/// The basic backend implementation.
92///
93/// This is the most primitive backend implementation: it owns its
94/// context, and backend features are directly called from it.
95///
96/// This implementation is useful when you need to call features in
97/// serie. If you need to call features in batch (parallel), see the
98/// [`pool::BackendPool`] implementation instead.
99pub struct Backend<C>
100where
101    C: BackendContext,
102{
103    /// The account configuration.
104    pub account_config: Arc<AccountConfig>,
105    /// The backend context.
106    pub context: Arc<C>,
107
108    /// The add folder backend feature.
109    pub add_folder: Option<BackendFeature<C, dyn AddFolder>>,
110    /// The list folders backend feature.
111    pub list_folders: Option<BackendFeature<C, dyn ListFolders>>,
112    /// The expunge folder backend feature.
113    pub expunge_folder: Option<BackendFeature<C, dyn ExpungeFolder>>,
114    /// The purge folder backend feature.
115    pub purge_folder: Option<BackendFeature<C, dyn PurgeFolder>>,
116    /// The delete folder backend feature.
117    pub delete_folder: Option<BackendFeature<C, dyn DeleteFolder>>,
118
119    /// The get envelope backend feature.
120    pub get_envelope: Option<BackendFeature<C, dyn GetEnvelope>>,
121    /// The list envelopes backend feature.
122    pub list_envelopes: Option<BackendFeature<C, dyn ListEnvelopes>>,
123    /// The thread envelopes backend feature.
124    #[cfg(feature = "thread")]
125    pub thread_envelopes: Option<BackendFeature<C, dyn ThreadEnvelopes>>,
126    /// The watch envelopes backend feature.
127    #[cfg(feature = "watch")]
128    pub watch_envelopes: Option<BackendFeature<C, dyn WatchEnvelopes>>,
129
130    /// The add flags backend feature.
131    pub add_flags: Option<BackendFeature<C, dyn AddFlags>>,
132    /// The set flags backend feature.
133    pub set_flags: Option<BackendFeature<C, dyn SetFlags>>,
134    /// The remove flags backend feature.
135    pub remove_flags: Option<BackendFeature<C, dyn RemoveFlags>>,
136
137    /// The add message backend feature.
138    pub add_message: Option<BackendFeature<C, dyn AddMessage>>,
139    /// The send message backend feature.
140    pub send_message: Option<BackendFeature<C, dyn SendMessage>>,
141    /// The peek messages backend feature.
142    pub peek_messages: Option<BackendFeature<C, dyn PeekMessages>>,
143    /// The get messages backend feature.
144    pub get_messages: Option<BackendFeature<C, dyn GetMessages>>,
145    /// The copy messages backend feature.
146    pub copy_messages: Option<BackendFeature<C, dyn CopyMessages>>,
147    /// The move messages backend feature.
148    pub move_messages: Option<BackendFeature<C, dyn MoveMessages>>,
149    /// The delete messages backend feature.
150    pub delete_messages: Option<BackendFeature<C, dyn DeleteMessages>>,
151    /// The delete messages backend feature.
152    pub remove_messages: Option<BackendFeature<C, dyn RemoveMessages>>,
153}
154
155impl<C: BackendContext> HasAccountConfig for Backend<C> {
156    fn account_config(&self) -> &AccountConfig {
157        &self.account_config
158    }
159}
160
161#[async_trait]
162impl<C: BackendContext> AddFolder for Backend<C> {
163    async fn add_folder(&self, folder: &str) -> AnyResult<()> {
164        self.add_folder
165            .as_ref()
166            .and_then(|feature| feature(&self.context))
167            .ok_or(Error::AddFolderNotAvailableError)?
168            .add_folder(folder)
169            .await
170    }
171}
172
173#[async_trait]
174impl<C: BackendContext> ListFolders for Backend<C> {
175    async fn list_folders(&self) -> AnyResult<Folders> {
176        self.list_folders
177            .as_ref()
178            .and_then(|feature| feature(&self.context))
179            .ok_or(Error::ListFoldersNotAvailableError)?
180            .list_folders()
181            .await
182    }
183}
184
185#[async_trait]
186impl<C: BackendContext> ExpungeFolder for Backend<C> {
187    async fn expunge_folder(&self, folder: &str) -> AnyResult<()> {
188        self.expunge_folder
189            .as_ref()
190            .and_then(|feature| feature(&self.context))
191            .ok_or(Error::ExpungeFolderNotAvailableError)?
192            .expunge_folder(folder)
193            .await
194    }
195}
196
197#[async_trait]
198impl<C: BackendContext> PurgeFolder for Backend<C> {
199    async fn purge_folder(&self, folder: &str) -> AnyResult<()> {
200        self.purge_folder
201            .as_ref()
202            .and_then(|feature| feature(&self.context))
203            .ok_or(Error::PurgeFolderNotAvailableError)?
204            .purge_folder(folder)
205            .await
206    }
207}
208
209#[async_trait]
210impl<C: BackendContext> DeleteFolder for Backend<C> {
211    async fn delete_folder(&self, folder: &str) -> AnyResult<()> {
212        self.delete_folder
213            .as_ref()
214            .and_then(|feature| feature(&self.context))
215            .ok_or(Error::DeleteFolderNotAvailableError)?
216            .delete_folder(folder)
217            .await
218    }
219}
220
221#[async_trait]
222impl<C: BackendContext> GetEnvelope for Backend<C> {
223    async fn get_envelope(&self, folder: &str, id: &SingleId) -> AnyResult<Envelope> {
224        self.get_envelope
225            .as_ref()
226            .and_then(|feature| feature(&self.context))
227            .ok_or(Error::GetEnvelopeNotAvailableError)?
228            .get_envelope(folder, id)
229            .await
230    }
231}
232
233#[async_trait]
234impl<C: BackendContext> ListEnvelopes for Backend<C> {
235    async fn list_envelopes(
236        &self,
237        folder: &str,
238        opts: ListEnvelopesOptions,
239    ) -> AnyResult<Envelopes> {
240        self.list_envelopes
241            .as_ref()
242            .and_then(|feature| feature(&self.context))
243            .ok_or(Error::ListEnvelopesNotAvailableError)?
244            .list_envelopes(folder, opts)
245            .await
246    }
247}
248
249#[cfg(feature = "thread")]
250#[async_trait]
251impl<C: BackendContext> ThreadEnvelopes for Backend<C> {
252    async fn thread_envelopes(
253        &self,
254        folder: &str,
255        opts: ListEnvelopesOptions,
256    ) -> AnyResult<ThreadedEnvelopes> {
257        self.thread_envelopes
258            .as_ref()
259            .and_then(|feature| feature(&self.context))
260            .ok_or(Error::ThreadEnvelopesNotAvailableError)?
261            .thread_envelopes(folder, opts)
262            .await
263    }
264
265    async fn thread_envelope(
266        &self,
267        folder: &str,
268        id: SingleId,
269        opts: ListEnvelopesOptions,
270    ) -> AnyResult<ThreadedEnvelopes> {
271        self.thread_envelopes
272            .as_ref()
273            .and_then(|feature| feature(&self.context))
274            .ok_or(Error::ThreadEnvelopesNotAvailableError)?
275            .thread_envelope(folder, id, opts)
276            .await
277    }
278}
279
280#[cfg(feature = "watch")]
281#[async_trait]
282impl<C: BackendContext> WatchEnvelopes for Backend<C> {
283    async fn watch_envelopes(
284        &self,
285        folder: &str,
286        wait_for_shutdown_request: Receiver<()>,
287        shutdown: Sender<()>,
288    ) -> AnyResult<()> {
289        self.watch_envelopes
290            .as_ref()
291            .and_then(|feature| feature(&self.context))
292            .ok_or(Error::WatchEnvelopesNotAvailableError)?
293            .watch_envelopes(folder, wait_for_shutdown_request, shutdown)
294            .await
295    }
296}
297
298#[async_trait]
299impl<C: BackendContext> AddFlags for Backend<C> {
300    async fn add_flags(&self, folder: &str, id: &Id, flags: &Flags) -> AnyResult<()> {
301        self.add_flags
302            .as_ref()
303            .and_then(|feature| feature(&self.context))
304            .ok_or(Error::AddFlagsNotAvailableError)?
305            .add_flags(folder, id, flags)
306            .await
307    }
308}
309
310#[async_trait]
311impl<C: BackendContext> SetFlags for Backend<C> {
312    async fn set_flags(&self, folder: &str, id: &Id, flags: &Flags) -> AnyResult<()> {
313        self.set_flags
314            .as_ref()
315            .and_then(|feature| feature(&self.context))
316            .ok_or(Error::SetFlagsNotAvailableError)?
317            .set_flags(folder, id, flags)
318            .await
319    }
320}
321
322#[async_trait]
323impl<C: BackendContext> RemoveFlags for Backend<C> {
324    async fn remove_flags(&self, folder: &str, id: &Id, flags: &Flags) -> AnyResult<()> {
325        self.remove_flags
326            .as_ref()
327            .and_then(|feature| feature(&self.context))
328            .ok_or(Error::RemoveFlagsNotAvailableError)?
329            .remove_flags(folder, id, flags)
330            .await
331    }
332}
333
334#[async_trait]
335impl<C: BackendContext> AddMessage for Backend<C> {
336    async fn add_message_with_flags(
337        &self,
338        folder: &str,
339        msg: &[u8],
340        flags: &Flags,
341    ) -> AnyResult<SingleId> {
342        self.add_message
343            .as_ref()
344            .and_then(|feature| feature(&self.context))
345            .ok_or(Error::AddMessageNotAvailableError)?
346            .add_message_with_flags(folder, msg, flags)
347            .await
348    }
349}
350
351#[async_trait]
352impl<C: BackendContext> SendMessage for Backend<C> {
353    async fn send_message(&self, msg: &[u8]) -> AnyResult<()> {
354        self.send_message
355            .as_ref()
356            .and_then(|feature| feature(&self.context))
357            .ok_or(Error::SendMessageNotAvailableError)?
358            .send_message(msg)
359            .await
360    }
361}
362
363#[async_trait]
364impl<C: BackendContext> PeekMessages for Backend<C> {
365    async fn peek_messages(&self, folder: &str, id: &Id) -> AnyResult<Messages> {
366        self.peek_messages
367            .as_ref()
368            .and_then(|feature| feature(&self.context))
369            .ok_or(Error::PeekMessagesNotAvailableError)?
370            .peek_messages(folder, id)
371            .await
372    }
373}
374
375#[async_trait]
376impl<C: BackendContext> GetMessages for Backend<C> {
377    async fn get_messages(&self, folder: &str, id: &Id) -> AnyResult<Messages> {
378        self.get_messages
379            .as_ref()
380            .and_then(|feature| feature(&self.context))
381            .ok_or(Error::GetMessagesNotAvailableError)?
382            .get_messages(folder, id)
383            .await
384    }
385}
386
387#[async_trait]
388impl<C: BackendContext> CopyMessages for Backend<C> {
389    async fn copy_messages(&self, from_folder: &str, to_folder: &str, id: &Id) -> AnyResult<()> {
390        self.copy_messages
391            .as_ref()
392            .and_then(|feature| feature(&self.context))
393            .ok_or(Error::CopyMessagesNotAvailableError)?
394            .copy_messages(from_folder, to_folder, id)
395            .await
396    }
397}
398
399#[async_trait]
400impl<C: BackendContext> MoveMessages for Backend<C> {
401    async fn move_messages(&self, from_folder: &str, to_folder: &str, id: &Id) -> AnyResult<()> {
402        self.move_messages
403            .as_ref()
404            .and_then(|feature| feature(&self.context))
405            .ok_or(Error::MoveMessagesNotAvailableError)?
406            .move_messages(from_folder, to_folder, id)
407            .await
408    }
409}
410
411#[async_trait]
412impl<C: BackendContext> DeleteMessages for Backend<C> {
413    async fn delete_messages(&self, folder: &str, id: &Id) -> AnyResult<()> {
414        self.delete_messages
415            .as_ref()
416            .and_then(|feature| feature(&self.context))
417            .ok_or(Error::DeleteMessagesNotAvailableError)?
418            .delete_messages(folder, id)
419            .await
420    }
421}
422
423#[async_trait]
424impl<C: BackendContext> RemoveMessages for Backend<C> {
425    async fn remove_messages(&self, folder: &str, id: &Id) -> AnyResult<()> {
426        self.remove_messages
427            .as_ref()
428            .and_then(|feature| feature(&self.context))
429            .ok_or(Error::RemoveMessagesNotAvailableError)?
430            .remove_messages(folder, id)
431            .await
432    }
433}
434
435/// Macro for defining [`BackendBuilder`] feature getter and setters.
436macro_rules! feature_accessors {
437    ($feat:ty) => {
438        paste! {
439            pub fn [<get_ $feat:snake>](
440                &self
441            ) -> Option<BackendFeature<CB::Context, dyn $feat>> {
442                match &self.[<$feat:snake>] {
443                    BackendFeatureSource::None => None,
444                    BackendFeatureSource::Context => self.ctx_builder.[<$feat:snake>]().clone(),
445                    BackendFeatureSource::Backend(f) => Some(f.clone()),
446                }
447            }
448
449            /// Set the given backend feature.
450            pub fn [<set_ $feat:snake>](
451                &mut self,
452                f: impl Into<BackendFeatureSource<CB::Context, dyn $feat>>,
453            ) {
454                self.[<$feat:snake>] = f.into();
455            }
456
457            /// Set the given backend feature, using the builder
458            /// pattern.
459            pub fn [<with_ $feat:snake>](
460                mut self,
461                f: impl Into<BackendFeatureSource<CB::Context, dyn $feat>>,
462            ) -> Self {
463                self.[<set_ $feat:snake>](f);
464                self
465            }
466
467            /// Disable the given backend feature, using the builder
468            /// pattern.
469            pub fn [<without_ $feat:snake>](mut self) -> Self {
470                self.[<set_ $feat:snake>](BackendFeatureSource::None);
471                self
472            }
473
474            /// Use the given backend feature from the context
475            /// builder, using the builder pattern.
476            pub fn [<with_context_ $feat:snake>](mut self) -> Self {
477                self.[<set_ $feat:snake>](BackendFeatureSource::Context);
478                self
479            }
480        }
481    };
482}
483
484/// The runtime backend builder.
485///
486/// The determination of backend's features occurs dynamically at
487/// runtime, making the utilization of traits and generics potentially
488/// less advantageous in this context. This consideration is
489/// particularly relevant if the client interface is an interactive
490/// shell (To Be Announced).
491///
492/// Furthermore, this design empowers the programmatic management of
493/// features during runtime.
494///
495/// Alternatively, users have the option to define their custom
496/// structs and implement the same traits as those implemented by
497/// `BackendBuilder`. This approach allows for the creation of bespoke
498/// functionality tailored to specific requirements.
499pub struct BackendBuilder<CB>
500where
501    CB: BackendContextBuilder,
502{
503    /// The account configuration.
504    pub account_config: Arc<AccountConfig>,
505    /// The backend context builder.
506    pub ctx_builder: CB,
507
508    /// The noop backend builder feature.
509    pub check_up: BackendFeatureSource<CB::Context, dyn CheckUp>,
510
511    /// The add folder backend builder feature.
512    pub add_folder: BackendFeatureSource<CB::Context, dyn AddFolder>,
513    /// The list folders backend builder feature.
514    pub list_folders: BackendFeatureSource<CB::Context, dyn ListFolders>,
515    /// The expunge folder backend builder feature.
516    pub expunge_folder: BackendFeatureSource<CB::Context, dyn ExpungeFolder>,
517    /// The purge folder backend builder feature.
518    pub purge_folder: BackendFeatureSource<CB::Context, dyn PurgeFolder>,
519    /// The delete folder backend builder feature.
520    pub delete_folder: BackendFeatureSource<CB::Context, dyn DeleteFolder>,
521
522    /// The get envelope backend builder feature.
523    pub get_envelope: BackendFeatureSource<CB::Context, dyn GetEnvelope>,
524    /// The list envelopes backend builder feature.
525    pub list_envelopes: BackendFeatureSource<CB::Context, dyn ListEnvelopes>,
526    /// The thread envelopes backend builder feature.
527    #[cfg(feature = "thread")]
528    pub thread_envelopes: BackendFeatureSource<CB::Context, dyn ThreadEnvelopes>,
529    /// The watch envelopes backend builder feature.
530    #[cfg(feature = "watch")]
531    pub watch_envelopes: BackendFeatureSource<CB::Context, dyn WatchEnvelopes>,
532
533    /// The add flags backend builder feature.
534    pub add_flags: BackendFeatureSource<CB::Context, dyn AddFlags>,
535    /// The set flags backend builder feature.
536    pub set_flags: BackendFeatureSource<CB::Context, dyn SetFlags>,
537    /// The remove flags backend builder feature.
538    pub remove_flags: BackendFeatureSource<CB::Context, dyn RemoveFlags>,
539
540    /// The add message backend builder feature.
541    pub add_message: BackendFeatureSource<CB::Context, dyn AddMessage>,
542    /// The send message backend builder feature.
543    pub send_message: BackendFeatureSource<CB::Context, dyn SendMessage>,
544    /// The peek messages backend builder feature.
545    pub peek_messages: BackendFeatureSource<CB::Context, dyn PeekMessages>,
546    /// The get messages backend builder feature.
547    pub get_messages: BackendFeatureSource<CB::Context, dyn GetMessages>,
548    /// The copy messages backend builder feature.
549    pub copy_messages: BackendFeatureSource<CB::Context, dyn CopyMessages>,
550    /// The move messages backend builder feature.
551    pub move_messages: BackendFeatureSource<CB::Context, dyn MoveMessages>,
552    /// The delete messages backend builder feature.
553    pub delete_messages: BackendFeatureSource<CB::Context, dyn DeleteMessages>,
554    /// The remove messages backend builder feature.
555    pub remove_messages: BackendFeatureSource<CB::Context, dyn RemoveMessages>,
556}
557
558impl<CB> BackendBuilder<CB>
559where
560    CB: BackendContextBuilder,
561{
562    feature_accessors!(CheckUp);
563    feature_accessors!(AddFolder);
564    feature_accessors!(ListFolders);
565    feature_accessors!(ExpungeFolder);
566    feature_accessors!(PurgeFolder);
567    feature_accessors!(DeleteFolder);
568    feature_accessors!(GetEnvelope);
569    feature_accessors!(ListEnvelopes);
570    #[cfg(feature = "thread")]
571    feature_accessors!(ThreadEnvelopes);
572    #[cfg(feature = "watch")]
573    feature_accessors!(WatchEnvelopes);
574    feature_accessors!(AddFlags);
575    feature_accessors!(SetFlags);
576    feature_accessors!(RemoveFlags);
577    feature_accessors!(AddMessage);
578    feature_accessors!(SendMessage);
579    feature_accessors!(PeekMessages);
580    feature_accessors!(GetMessages);
581    feature_accessors!(CopyMessages);
582    feature_accessors!(MoveMessages);
583    feature_accessors!(DeleteMessages);
584    feature_accessors!(RemoveMessages);
585
586    /// Create a new backend builder using the given backend context
587    /// builder.
588    ///
589    /// All features are taken from the context by default.
590    pub fn new(account_config: Arc<AccountConfig>, ctx_builder: CB) -> Self {
591        Self {
592            account_config,
593            ctx_builder,
594
595            check_up: BackendFeatureSource::Context,
596
597            add_folder: BackendFeatureSource::Context,
598            list_folders: BackendFeatureSource::Context,
599            expunge_folder: BackendFeatureSource::Context,
600            purge_folder: BackendFeatureSource::Context,
601            delete_folder: BackendFeatureSource::Context,
602
603            get_envelope: BackendFeatureSource::Context,
604            list_envelopes: BackendFeatureSource::Context,
605            #[cfg(feature = "thread")]
606            thread_envelopes: BackendFeatureSource::Context,
607            #[cfg(feature = "watch")]
608            watch_envelopes: BackendFeatureSource::Context,
609
610            add_flags: BackendFeatureSource::Context,
611            set_flags: BackendFeatureSource::Context,
612            remove_flags: BackendFeatureSource::Context,
613
614            add_message: BackendFeatureSource::Context,
615            send_message: BackendFeatureSource::Context,
616            peek_messages: BackendFeatureSource::Context,
617            get_messages: BackendFeatureSource::Context,
618            copy_messages: BackendFeatureSource::Context,
619            move_messages: BackendFeatureSource::Context,
620            delete_messages: BackendFeatureSource::Context,
621            remove_messages: BackendFeatureSource::Context,
622        }
623    }
624
625    /// Disable all features for this backend builder.
626    pub fn without_features(mut self) -> Self {
627        self.set_list_folders(BackendFeatureSource::None);
628        self
629    }
630
631    pub async fn check_up(self) -> AnyResult<()> {
632        let ctx = self.ctx_builder.clone().build().await?;
633        match self.get_check_up().and_then(move |f| f(&ctx)) {
634            Some(f) => f.check_up().await,
635            None => Ok(()),
636        }
637    }
638
639    pub async fn build(self) -> AnyResult<Backend<CB::Context>> {
640        let add_folder = self.get_add_folder();
641        let list_folders = self.get_list_folders();
642        let expunge_folder = self.get_expunge_folder();
643        let purge_folder = self.get_purge_folder();
644        let delete_folder = self.get_delete_folder();
645
646        let get_envelope = self.get_get_envelope();
647        let list_envelopes = self.get_list_envelopes();
648        #[cfg(feature = "thread")]
649        let thread_envelopes = self.get_thread_envelopes();
650        #[cfg(feature = "watch")]
651        let watch_envelopes = self.get_watch_envelopes();
652
653        let add_flags = self.get_add_flags();
654        let set_flags = self.get_set_flags();
655        let remove_flags = self.get_remove_flags();
656
657        let add_message = self.get_add_message();
658        let send_message = self.get_send_message();
659        let peek_messages = self.get_peek_messages();
660        let get_messages = self.get_get_messages();
661        let copy_messages = self.get_copy_messages();
662        let move_messages = self.get_move_messages();
663        let delete_messages = self.get_delete_messages();
664        let remove_messages = self.get_remove_messages();
665
666        Ok(Backend {
667            account_config: self.account_config,
668            context: Arc::new(self.ctx_builder.build().await?),
669
670            add_folder,
671            list_folders,
672            expunge_folder,
673            purge_folder,
674            delete_folder,
675
676            get_envelope,
677            list_envelopes,
678            #[cfg(feature = "thread")]
679            thread_envelopes,
680            #[cfg(feature = "watch")]
681            watch_envelopes,
682
683            add_flags,
684            set_flags,
685            remove_flags,
686
687            add_message,
688            send_message,
689            peek_messages,
690            get_messages,
691            copy_messages,
692            move_messages,
693            delete_messages,
694            remove_messages,
695        })
696    }
697}
698
699#[async_trait]
700impl<CB> Clone for BackendBuilder<CB>
701where
702    CB: BackendContextBuilder,
703{
704    fn clone(&self) -> Self {
705        Self {
706            account_config: self.account_config.clone(),
707            ctx_builder: self.ctx_builder.clone(),
708
709            check_up: self.check_up.clone(),
710
711            add_folder: self.add_folder.clone(),
712            list_folders: self.list_folders.clone(),
713            expunge_folder: self.expunge_folder.clone(),
714            purge_folder: self.purge_folder.clone(),
715            delete_folder: self.delete_folder.clone(),
716
717            get_envelope: self.get_envelope.clone(),
718            list_envelopes: self.list_envelopes.clone(),
719            #[cfg(feature = "thread")]
720            thread_envelopes: self.thread_envelopes.clone(),
721            #[cfg(feature = "watch")]
722            watch_envelopes: self.watch_envelopes.clone(),
723
724            add_flags: self.add_flags.clone(),
725            set_flags: self.set_flags.clone(),
726            remove_flags: self.remove_flags.clone(),
727
728            add_message: self.add_message.clone(),
729            send_message: self.send_message.clone(),
730            peek_messages: self.peek_messages.clone(),
731            get_messages: self.get_messages.clone(),
732            copy_messages: self.copy_messages.clone(),
733            move_messages: self.move_messages.clone(),
734            delete_messages: self.delete_messages.clone(),
735            remove_messages: self.remove_messages.clone(),
736        }
737    }
738}
739
740#[cfg(feature = "sync")]
741impl<CB> SyncHash for BackendBuilder<CB>
742where
743    CB: BackendContextBuilder + SyncHash,
744{
745    fn sync_hash(&self, state: &mut DefaultHasher) {
746        self.ctx_builder.sync_hash(state)
747    }
748}