pub trait SomeBackendContextBuilderMapper<CB>
where Self: BackendContextBuilder, Self::Context: AsRef<Option<CB::Context>> + 'static, CB: BackendContextBuilder, CB::Context: BackendContext + 'static,
{
Show 20 methods // Provided methods fn map_feature<T: ?Sized + 'static>( &self, f: Option<BackendFeature<CB::Context, T>> ) -> Option<BackendFeature<Self::Context, T>> { ... } fn check_up_with_some( &self, cb: &Option<CB> ) -> Option<BackendFeature<Self::Context, dyn CheckUp>> { ... } fn add_folder_with_some( &self, cb: &Option<CB> ) -> Option<BackendFeature<Self::Context, dyn AddFolder>> { ... } fn list_folders_with_some( &self, cb: &Option<CB> ) -> Option<BackendFeature<Self::Context, dyn ListFolders>> { ... } fn expunge_folder_with_some( &self, cb: &Option<CB> ) -> Option<BackendFeature<Self::Context, dyn ExpungeFolder>> { ... } fn purge_folder_with_some( &self, cb: &Option<CB> ) -> Option<BackendFeature<Self::Context, dyn PurgeFolder>> { ... } fn delete_folder_with_some( &self, cb: &Option<CB> ) -> Option<BackendFeature<Self::Context, dyn DeleteFolder>> { ... } fn get_envelope_with_some( &self, cb: &Option<CB> ) -> Option<BackendFeature<Self::Context, dyn GetEnvelope>> { ... } fn list_envelopes_with_some( &self, cb: &Option<CB> ) -> Option<BackendFeature<Self::Context, dyn ListEnvelopes>> { ... } fn watch_envelopes_with_some( &self, cb: &Option<CB> ) -> Option<BackendFeature<Self::Context, dyn WatchEnvelopes>> { ... } fn add_flags_with_some( &self, cb: &Option<CB> ) -> Option<BackendFeature<Self::Context, dyn AddFlags>> { ... } fn set_flags_with_some( &self, cb: &Option<CB> ) -> Option<BackendFeature<Self::Context, dyn SetFlags>> { ... } fn remove_flags_with_some( &self, cb: &Option<CB> ) -> Option<BackendFeature<Self::Context, dyn RemoveFlags>> { ... } fn add_message_with_some( &self, cb: &Option<CB> ) -> Option<BackendFeature<Self::Context, dyn AddMessage>> { ... } fn send_message_with_some( &self, cb: &Option<CB> ) -> Option<BackendFeature<Self::Context, dyn SendMessage>> { ... } fn peek_messages_with_some( &self, cb: &Option<CB> ) -> Option<BackendFeature<Self::Context, dyn PeekMessages>> { ... } fn get_messages_with_some( &self, cb: &Option<CB> ) -> Option<BackendFeature<Self::Context, dyn GetMessages>> { ... } fn copy_messages_with_some( &self, cb: &Option<CB> ) -> Option<BackendFeature<Self::Context, dyn CopyMessages>> { ... } fn move_messages_with_some( &self, cb: &Option<CB> ) -> Option<BackendFeature<Self::Context, dyn MoveMessages>> { ... } fn delete_messages_with_some( &self, cb: &Option<CB> ) -> Option<BackendFeature<Self::Context, dyn DeleteMessages>> { ... }
}
Expand description

Map a backend feature from subcontext B to context A.

This is useful when you have a context composed of multiple subcontexts. It prevents you to manually map the feature.

See a usage example at ../../tests/dynamic_backend.rs.

use async_trait::async_trait;
use email::{
    account::config::{passwd::PasswdConfig, AccountConfig},
    backend::{
        context::BackendContextBuilder, feature::BackendFeature, macros::BackendContext,
        mapper::SomeBackendContextBuilderMapper, Backend, BackendBuilder,
    },
    folder::{list::ListFolders, Folder, FolderKind},
    imap::{
        config::{ImapAuthConfig, ImapConfig, ImapEncryptionKind},
        ImapContextBuilder, ImapContextSync,
    },
    smtp::{SmtpContextBuilder, SmtpContextSync},
    AnyResult,
};
use email_testing_server::with_email_testing_server;
use secret::Secret;
use std::sync::Arc;

#[tokio::test(flavor = "multi_thread")]
async fn test_dynamic_backend() {
    env_logger::builder().is_test(true).init();

    with_email_testing_server(|ports| async move {
        let account_config = Arc::new(AccountConfig::default());

        let imap_config = Arc::new(ImapConfig {
            host: "localhost".into(),
            port: ports.imap,
            encryption: Some(ImapEncryptionKind::None),
            login: "bob".into(),
            auth: ImapAuthConfig::Passwd(PasswdConfig(Secret::new_raw("password"))),
            ..Default::default()
        });

        // 1. define custom context

        #[derive(BackendContext)]
        struct DynamicContext {
            imap: Option<ImapContextSync>,
            smtp: Option<SmtpContextSync>,
        }

        // 2. implement AsRef for mapping features

        impl AsRef<Option<ImapContextSync>> for DynamicContext {
            fn as_ref(&self) -> &Option<ImapContextSync> {
                &self.imap
            }
        }

        impl AsRef<Option<SmtpContextSync>> for DynamicContext {
            fn as_ref(&self) -> &Option<SmtpContextSync> {
                &self.smtp
            }
        }

        // 3. define custom context builder

        #[derive(Clone)]
        struct DynamicContextBuilder {
            imap: Option<ImapContextBuilder>,
            smtp: Option<SmtpContextBuilder>,
        }

        // 4. implement backend context builder

        #[async_trait]
        impl BackendContextBuilder for DynamicContextBuilder {
            type Context = DynamicContext;

            // override the list folders feature using the imap builder
            fn list_folders(&self) -> Option<BackendFeature<Self::Context, dyn ListFolders>> {
                self.list_folders_with_some(&self.imap)
            }

            async fn build(self) -> AnyResult<Self::Context> {
                let imap = match self.imap {
                    Some(imap) => Some(imap.build().await?),
                    None => None,
                };

                let smtp = match self.smtp {
                    Some(smtp) => Some(smtp.build().await?),
                    None => None,
                };

                Ok(DynamicContext { imap, smtp })
            }
        }

        // 5. plug all together

        let ctx_builder = DynamicContextBuilder {
            imap: Some(ImapContextBuilder::new(
                account_config.clone(),
                imap_config.clone(),
            )),
            smtp: None,
        };
        let backend_builder = BackendBuilder::new(account_config.clone(), ctx_builder);
        let backend: Backend<DynamicContext> = backend_builder.build().await.unwrap();
        let folders = backend.list_folders().await.unwrap();

        assert!(folders.contains(&Folder {
            kind: Some(FolderKind::Inbox),
            name: "INBOX".into(),
            desc: "".into()
        }));
    })
    .await
}

Provided Methods§

source

fn map_feature<T: ?Sized + 'static>( &self, f: Option<BackendFeature<CB::Context, T>> ) -> Option<BackendFeature<Self::Context, T>>

source

fn check_up_with_some( &self, cb: &Option<CB> ) -> Option<BackendFeature<Self::Context, dyn CheckUp>>

source

fn add_folder_with_some( &self, cb: &Option<CB> ) -> Option<BackendFeature<Self::Context, dyn AddFolder>>

source

fn list_folders_with_some( &self, cb: &Option<CB> ) -> Option<BackendFeature<Self::Context, dyn ListFolders>>

source

fn expunge_folder_with_some( &self, cb: &Option<CB> ) -> Option<BackendFeature<Self::Context, dyn ExpungeFolder>>

source

fn purge_folder_with_some( &self, cb: &Option<CB> ) -> Option<BackendFeature<Self::Context, dyn PurgeFolder>>

source

fn delete_folder_with_some( &self, cb: &Option<CB> ) -> Option<BackendFeature<Self::Context, dyn DeleteFolder>>

source

fn get_envelope_with_some( &self, cb: &Option<CB> ) -> Option<BackendFeature<Self::Context, dyn GetEnvelope>>

source

fn list_envelopes_with_some( &self, cb: &Option<CB> ) -> Option<BackendFeature<Self::Context, dyn ListEnvelopes>>

source

fn watch_envelopes_with_some( &self, cb: &Option<CB> ) -> Option<BackendFeature<Self::Context, dyn WatchEnvelopes>>

source

fn add_flags_with_some( &self, cb: &Option<CB> ) -> Option<BackendFeature<Self::Context, dyn AddFlags>>

source

fn set_flags_with_some( &self, cb: &Option<CB> ) -> Option<BackendFeature<Self::Context, dyn SetFlags>>

source

fn remove_flags_with_some( &self, cb: &Option<CB> ) -> Option<BackendFeature<Self::Context, dyn RemoveFlags>>

source

fn add_message_with_some( &self, cb: &Option<CB> ) -> Option<BackendFeature<Self::Context, dyn AddMessage>>

source

fn send_message_with_some( &self, cb: &Option<CB> ) -> Option<BackendFeature<Self::Context, dyn SendMessage>>

source

fn peek_messages_with_some( &self, cb: &Option<CB> ) -> Option<BackendFeature<Self::Context, dyn PeekMessages>>

source

fn get_messages_with_some( &self, cb: &Option<CB> ) -> Option<BackendFeature<Self::Context, dyn GetMessages>>

source

fn copy_messages_with_some( &self, cb: &Option<CB> ) -> Option<BackendFeature<Self::Context, dyn CopyMessages>>

source

fn move_messages_with_some( &self, cb: &Option<CB> ) -> Option<BackendFeature<Self::Context, dyn MoveMessages>>

source

fn delete_messages_with_some( &self, cb: &Option<CB> ) -> Option<BackendFeature<Self::Context, dyn DeleteMessages>>

Object Safety§

This trait is not object safe.

Implementors§

source§

impl<CB1, CB2> SomeBackendContextBuilderMapper<CB2> for CB1
where CB1: BackendContextBuilder, CB1::Context: AsRef<Option<CB2::Context>> + 'static, CB2: BackendContextBuilder, CB2::Context: BackendContext + 'static,

Automatically implement SomeBackendContextBuilderMapper.