email::backend::mapper

Trait SomeBackendContextBuilderMapper

Source
pub trait SomeBackendContextBuilderMapper<CB>
where Self: BackendContextBuilder, Self::Context: AsRef<Option<CB::Context>> + 'static, CB: BackendContextBuilder, CB::Context: BackendContext + 'static,
{
Show 21 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 thread_envelopes_with_some( &self, cb: &Option<CB>, ) -> Option<BackendFeature<Self::Context, dyn ThreadEnvelopes>> { ... } 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.

#![cfg(feature = "imap")]

use std::sync::Arc;

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

#[test_log::test(tokio::test(flavor = "multi_thread"))]
async fn test_dynamic_backend() {
    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::Password(PasswordConfig(Secret::new_raw("password"))),
            ..Default::default()
        });

        // 1. define custom context

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

        // 2. implement AsRef for mapping features

        impl AsRef<Option<ImapContext>> for DynamicContext {
            fn as_ref(&self) -> &Option<ImapContext> {
                &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 thread_envelopes_with_some( &self, cb: &Option<CB>, ) -> Option<BackendFeature<Self::Context, dyn ThreadEnvelopes>>

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>>

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety", so 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.