use paste::paste;
use std::sync::Arc;
use crate::{
envelope::{get::GetEnvelope, list::ListEnvelopes, watch::WatchEnvelopes},
flag::{add::AddFlags, remove::RemoveFlags, set::SetFlags},
folder::{
add::AddFolder, delete::DeleteFolder, expunge::ExpungeFolder, list::ListFolders,
purge::PurgeFolder,
},
message::{
add::AddMessage, copy::CopyMessages, delete::DeleteMessages, get::GetMessages,
peek::PeekMessages, r#move::MoveMessages, send::SendMessage,
},
};
use super::{
context::{BackendContext, BackendContextBuilder},
feature::{BackendFeature, CheckUp},
};
macro_rules! some_feature_mapper {
($feat:ty) => {
paste! {
fn [<$feat:snake _with_some>](
&self,
cb: &Option<CB>,
) -> Option<BackendFeature<Self::Context, dyn $feat>> {
let cb = cb.as_ref()?;
self.map_feature(cb.[<$feat:snake>]())
}
}
};
}
#[doc = include_str!("../../tests/dynamic_backend.rs")]
pub trait SomeBackendContextBuilderMapper<CB>
where
Self: BackendContextBuilder,
Self::Context: AsRef<Option<CB::Context>> + 'static,
CB: BackendContextBuilder,
CB::Context: BackendContext + 'static,
{
fn map_feature<T: ?Sized + 'static>(
&self,
f: Option<BackendFeature<CB::Context, T>>,
) -> Option<BackendFeature<Self::Context, T>> {
let f = f?;
Some(Arc::new(move |ctx| f(ctx.as_ref().as_ref()?)))
}
some_feature_mapper!(CheckUp);
some_feature_mapper!(AddFolder);
some_feature_mapper!(ListFolders);
some_feature_mapper!(ExpungeFolder);
some_feature_mapper!(PurgeFolder);
some_feature_mapper!(DeleteFolder);
some_feature_mapper!(GetEnvelope);
some_feature_mapper!(ListEnvelopes);
some_feature_mapper!(WatchEnvelopes);
some_feature_mapper!(AddFlags);
some_feature_mapper!(SetFlags);
some_feature_mapper!(RemoveFlags);
some_feature_mapper!(AddMessage);
some_feature_mapper!(SendMessage);
some_feature_mapper!(PeekMessages);
some_feature_mapper!(GetMessages);
some_feature_mapper!(CopyMessages);
some_feature_mapper!(MoveMessages);
some_feature_mapper!(DeleteMessages);
}
impl<CB1, CB2> SomeBackendContextBuilderMapper<CB2> for CB1
where
CB1: BackendContextBuilder,
CB1::Context: AsRef<Option<CB2::Context>> + 'static,
CB2: BackendContextBuilder,
CB2::Context: BackendContext + 'static,
{
}
macro_rules! feature_mapper {
($feat:ty) => {
paste! {
fn [<$feat:snake _with>] (
&self,
cb: &CB,
) -> Option<BackendFeature<Self::Context, dyn $feat>> {
self.map_feature(cb.[<$feat:snake>]())
}
}
};
}
pub trait BackendContextBuilderMapper<CB>
where
Self: BackendContextBuilder,
Self::Context: AsRef<CB::Context> + 'static,
CB: BackendContextBuilder,
CB::Context: BackendContext + 'static,
{
fn map_feature<T: ?Sized + 'static>(
&self,
f: Option<BackendFeature<CB::Context, T>>,
) -> Option<BackendFeature<Self::Context, T>> {
let f = f?;
Some(Arc::new(move |ctx| f(ctx.as_ref())))
}
feature_mapper!(AddFolder);
feature_mapper!(ListFolders);
feature_mapper!(ExpungeFolder);
feature_mapper!(PurgeFolder);
feature_mapper!(DeleteFolder);
feature_mapper!(GetEnvelope);
feature_mapper!(ListEnvelopes);
feature_mapper!(WatchEnvelopes);
feature_mapper!(AddFlags);
feature_mapper!(SetFlags);
feature_mapper!(RemoveFlags);
feature_mapper!(AddMessage);
feature_mapper!(SendMessage);
feature_mapper!(PeekMessages);
feature_mapper!(GetMessages);
feature_mapper!(CopyMessages);
feature_mapper!(MoveMessages);
feature_mapper!(DeleteMessages);
}
impl<CB1, CB2> BackendContextBuilderMapper<CB2> for CB1
where
CB1: BackendContextBuilder,
CB1::Context: AsRef<CB2::Context> + 'static,
CB2: BackendContextBuilder,
CB2::Context: BackendContext + 'static,
{
}