use std::sync::Arc;
use std::fmt::Debug;
use futures::{ future::{self, Either}, Future, IntoFuture };
use utils::SendBoxFuture;
use headers::header_components::{
MessageId, ContentId
};
use crate::{
resource::{Source, Data, EncData, Resource},
error::ResourceLoadingError
};
pub enum MaybeEncData {
Data(Data),
EncData(EncData)
}
impl MaybeEncData {
pub fn to_resource(self) -> Resource {
match self {
MaybeEncData::Data(data) => Resource::Data(data),
MaybeEncData::EncData(enc_data) => Resource::EncData(enc_data)
}
}
pub fn encode(self, ctx: &impl Context)
-> impl Future<Item=EncData,Error=ResourceLoadingError>
{
match self {
MaybeEncData::Data(data) => Either::A(ctx.load_transfer_encoded_resource(&Resource::Data(data))),
MaybeEncData::EncData(enc) => Either::B(future::ok(enc))
}
}
}
pub trait Context: Debug + Clone + Send + Sync + 'static {
fn load_resource(&self, source: &Source)
-> SendBoxFuture<MaybeEncData, ResourceLoadingError>;
fn load_transfer_encoded_resource(&self, resource: &Resource)
-> SendBoxFuture<EncData, ResourceLoadingError>
{
default_impl_for_load_transfer_encoded_resource(self, resource)
}
fn generate_message_id(&self) -> MessageId;
fn generate_content_id(&self) -> ContentId;
fn offload<F>(&self, fut: F) -> SendBoxFuture<F::Item, F::Error>
where F: Future + Send + 'static,
F::Item: Send + 'static,
F::Error: Send + 'static;
fn offload_fn<FN, I>(&self, func: FN ) -> SendBoxFuture<I::Item, I::Error>
where FN: FnOnce() -> I + Send + 'static,
I: IntoFuture + 'static,
I::Future: Send + 'static,
I::Item: Send + 'static,
I::Error: Send + 'static
{
self.offload( future::lazy( func ) )
}
}
pub fn default_impl_for_load_transfer_encoded_resource(ctx: &impl Context, resource: &Resource)
-> SendBoxFuture<EncData, ResourceLoadingError>
{
match resource {
Resource::Source(source) => {
let ctx2 = ctx.clone();
let fut = ctx.load_resource(&source)
.and_then(move |me_data| {
match me_data {
MaybeEncData::Data(data) => {
Either::A(ctx2.offload_fn(move || Ok(data.transfer_encode(Default::default()))))
},
MaybeEncData::EncData(enc_data) => {
Either::B(future::ok(enc_data))
}
}
});
Box::new(fut)
},
Resource::Data(data) => {
let data = data.clone();
ctx.offload_fn(move || Ok(data.transfer_encode(Default::default())))
},
Resource::EncData(enc_data) => {
Box::new(future::ok(enc_data.clone()))
}
}
}
pub trait ResourceLoaderComponent: Debug + Send + Sync + 'static {
fn load_resource(&self, source: &Source, ctx: &impl Context)
-> SendBoxFuture<MaybeEncData, ResourceLoadingError>;
fn load_transfer_encoded_resource(&self, resource: &Resource, ctx: &impl Context)
-> SendBoxFuture<EncData, ResourceLoadingError>
{
default_impl_for_load_transfer_encoded_resource(ctx, resource)
}
}
pub trait OffloaderComponent: Debug + Send + Sync + 'static {
fn offload<F>(&self, fut: F) -> SendBoxFuture<F::Item, F::Error>
where F: Future + Send + 'static,
F::Item: Send+'static,
F::Error: Send+'static;
}
pub trait MailIdGenComponent: Debug + Send + Sync + 'static {
fn generate_message_id(&self) -> MessageId;
fn generate_content_id(&self) -> ContentId;
}
#[derive(Debug)]
pub struct CompositeContext<
R: ResourceLoaderComponent,
O: OffloaderComponent,
M: MailIdGenComponent
>{
inner: Arc<(R, O, M)>,
}
impl<R, O, M> Clone for CompositeContext<R, O, M>
where R: ResourceLoaderComponent,
O: OffloaderComponent,
M: MailIdGenComponent
{
fn clone(&self) -> Self {
CompositeContext {
inner: self.inner.clone(),
}
}
}
impl<R, O, M> CompositeContext<R, O, M>
where R: ResourceLoaderComponent,
O: OffloaderComponent,
M: MailIdGenComponent
{
pub fn new(resource_loader: R, offloader: O, message_id_gen: M) -> Self {
CompositeContext {
inner: Arc::new((resource_loader, offloader, message_id_gen)),
}
}
pub fn resource_loader(&self) -> &R {
&self.inner.0
}
pub fn offloader(&self) -> &O {
&self.inner.1
}
pub fn id_gen(&self) -> &M {
&self.inner.2
}
}
impl<R, O, M> Context for CompositeContext<R, O, M>
where R: ResourceLoaderComponent,
O: OffloaderComponent,
M: MailIdGenComponent
{
fn load_resource(&self, source: &Source)
-> SendBoxFuture<MaybeEncData, ResourceLoadingError>
{
self.resource_loader().load_resource(source, self)
}
fn load_transfer_encoded_resource(&self, resource: &Resource)
-> SendBoxFuture<EncData, ResourceLoadingError>
{
self.resource_loader().load_transfer_encoded_resource(resource, self)
}
fn offload<F>(&self, fut: F) -> SendBoxFuture<F::Item, F::Error>
where F: Future + Send + 'static,
F::Item: Send+'static,
F::Error: Send+'static
{
self.offloader().offload(fut)
}
fn generate_content_id(&self) -> ContentId {
self.id_gen().generate_content_id()
}
fn generate_message_id(&self) -> MessageId {
self.id_gen().generate_message_id()
}
}
impl<C> MailIdGenComponent for C
where C: Context
{
fn generate_message_id(&self) -> MessageId {
<Self as Context>::generate_message_id(self)
}
fn generate_content_id(&self) -> ContentId {
<Self as Context>::generate_content_id(self)
}
}
impl<C> OffloaderComponent for C
where C: Context
{
fn offload<F>(&self, fut: F) -> SendBoxFuture<F::Item, F::Error>
where F: Future + Send + 'static,
F::Item: Send+'static,
F::Error: Send+'static
{
<Self as Context>::offload(self, fut)
}
}
impl<C> ResourceLoaderComponent for C
where C: Context
{
fn load_resource(&self, source: &Source, _: &impl Context)
-> SendBoxFuture<MaybeEncData, ResourceLoadingError>
{
<Self as Context>::load_resource(self, source)
}
fn load_transfer_encoded_resource(&self, resource: &Resource, _: &impl Context)
-> SendBoxFuture<EncData, ResourceLoadingError>
{
<Self as Context>::load_transfer_encoded_resource(self, resource)
}
}