diff options
Diffstat (limited to 'template/src/lib.rs')
-rw-r--r-- | template/src/lib.rs | 202 |
1 files changed, 98 insertions, 104 deletions
diff --git a/template/src/lib.rs b/template/src/lib.rs index be3ce45..f0763fa 100644 --- a/template/src/lib.rs +++ b/template/src/lib.rs @@ -1,63 +1,52 @@ extern crate failure; -extern crate serde; extern crate futures; +#[cfg(feature = "handlebars")] +extern crate handlebars as hbs; extern crate mail_core; extern crate mail_headers; -extern crate vec1; -extern crate toml; extern crate maybe_owned; -#[cfg(feature="handlebars")] -extern crate handlebars as hbs; +extern crate serde; +extern crate toml; +extern crate vec1; -#[cfg(all(feature="handlebars", not(feature="handlebars-bindings")))] +#[cfg(all(feature = "handlebars", not(feature = "handlebars-bindings")))] compile_error!("use feature `handlebars-bindings` instead of opt-dep-auto-feature `handlebars`"); use std::{ - fs, collections::HashMap, fmt::Debug, + fs, + ops::Deref, path::{Path, PathBuf}, - ops::Deref }; -use serde::{ - Serialize, - Deserialize -}; use failure::Error; use futures::{ - Future, Poll, Async, - try_ready, - future::{self, Join, Either} + future::{self, Either, Join}, + try_ready, Async, Future, Poll, }; -use vec1::Vec1; use maybe_owned::MaybeOwned; +use serde::{Deserialize, Serialize}; +use vec1::Vec1; use mail_core::{ - Resource, - Data, Metadata, - Context, ResourceContainerLoadingFuture, - compose::{MailParts, BodyPart}, - Mail -}; -use mail_headers::{ - HeaderKind, Header, - header_components::MediaType, - headers + compose::{BodyPart, MailParts}, + Context, Data, Mail, Metadata, Resource, ResourceContainerLoadingFuture, }; +use mail_headers::{header_components::MediaType, headers, Header, HeaderKind}; +mod additional_cid; mod base_dir; +pub mod error; mod path_rebase; -mod additional_cid; pub mod serde_impl; -pub mod error; -#[cfg(feature="handlebars")] +#[cfg(feature = "handlebars")] pub mod handlebars; +pub use self::additional_cid::*; pub use self::base_dir::*; pub use self::path_rebase::*; -pub use self::additional_cid::*; /// Trait used to bind/implement template engines. pub trait TemplateEngine: Sized { @@ -65,11 +54,12 @@ pub trait TemplateEngine: Sized { type LazyBodyTemplate: PathRebaseable + Debug + Send + Serialize + for<'a> Deserialize<'a>; - fn load_body_template(&mut self, tmpl: Self::LazyBodyTemplate) - -> Result<BodyTemplate<Self>, Error>; + fn load_body_template( + &mut self, + tmpl: Self::LazyBodyTemplate, + ) -> Result<BodyTemplate<Self>, Error>; - fn load_subject_template(&mut self, template_string: String) - -> Result<Self::Id, Error>; + fn load_subject_template(&mut self, template_string: String) -> Result<Self::Id, Error>; } /// Additional trait a template engine needs to implement for the types it can process as input. @@ -77,12 +67,11 @@ pub trait TemplateEngine: Sized { /// This could for example be implemented in a wild card impl for the template engine for /// any data `D` which implements `Serialize`. pub trait TemplateEngineCanHandleData<D>: TemplateEngine { - fn render<'r, 'a>( &'r self, id: &'r Self::Id, data: &'r D, - additional_cids: AdditionalCIds<'r> + additional_cids: AdditionalCIds<'r>, ) -> Result<String, Error>; } @@ -93,45 +82,48 @@ pub trait TemplateEngineCanHandleData<D>: TemplateEngine { pub fn load_toml_template_from_path<TE, C>( engine: TE, path: PathBuf, - ctx: &C -) -> impl Future<Item=Template<TE>, Error=Error> - where TE: TemplateEngine + 'static, C: Context + ctx: &C, +) -> impl Future<Item = Template<TE>, Error = Error> +where + TE: TemplateEngine + 'static, + C: Context, { - let ctx2 = ctx.clone(); ctx.offload_fn(move || { let content = fs::read_to_string(&path)?; let base: serde_impl::TemplateBase<TE> = toml::from_str(&content)?; - let base_dir = path.parent().unwrap_or_else(||Path::new(".")); + let base_dir = path.parent().unwrap_or_else(|| Path::new(".")); let base_dir = CwdBaseDir::from_path(base_dir)?; Ok((base, base_dir)) - }).and_then(move |(base, base_dir)| base.load(engine, base_dir, &ctx2)) + }) + .and_then(move |(base, base_dir)| base.load(engine, base_dir, &ctx2)) } /// Load a template as described in a toml string; pub fn load_toml_template_from_str<TE, C>( engine: TE, content: &str, - ctx: &C -) -> impl Future<Item=Template<TE>, Error=Error> - where TE: TemplateEngine, C: Context + ctx: &C, +) -> impl Future<Item = Template<TE>, Error = Error> +where + TE: TemplateEngine, + C: Context, { - let base: serde_impl::TemplateBase<TE> = - match toml::from_str(content) { - Ok(base) => base, - Err(err) => { return Either::B(future::err(Error::from(err))); } - }; + let base: serde_impl::TemplateBase<TE> = match toml::from_str(content) { + Ok(base) => base, + Err(err) => { + return Either::B(future::err(Error::from(err))); + } + }; - let base_dir = - match CwdBaseDir::from_path(Path::new(".")) { - Ok(base_dir) => base_dir, - Err(err) => { return Either::B(future::err(Error::from(err))) } - }; + let base_dir = match CwdBaseDir::from_path(Path::new(".")) { + Ok(base_dir) => base_dir, + Err(err) => return Either::B(future::err(Error::from(err))), + }; Either::A(base.load(engine, base_dir, ctx)) } - /// A Mail template. #[derive(Debug)] pub struct Template<TE: TemplateEngine> { @@ -149,7 +141,8 @@ pub struct Template<TE: TemplateEngine> { } impl<TE> Template<TE> - where TE: TemplateEngine +where + TE: TemplateEngine, { pub fn inline_embeddings(&self) -> &HashMap<String, Resource> { &self.embeddings @@ -172,17 +165,17 @@ impl<TE> Template<TE> } } - /// Represents one of potentially many alternate bodies in a template. #[derive(Debug)] pub struct BodyTemplate<TE: TemplateEngine> { pub template_id: TE::Id, pub media_type: MediaType, - pub inline_embeddings: HashMap<String, Resource> + pub inline_embeddings: HashMap<String, Resource>, } impl<TE> BodyTemplate<TE> - where TE: TemplateEngine +where + TE: TemplateEngine, { pub fn template_id(&self) -> &TE::Id { &self.template_id @@ -200,11 +193,12 @@ impl<TE> BodyTemplate<TE> /// Represents a template used for generating the subject of a mail. #[derive(Debug)] pub struct Subject<TE: TemplateEngine> { - template_id: TE::Id + template_id: TE::Id, } impl<TE> Subject<TE> - where TE: TemplateEngine +where + TE: TemplateEngine, { pub fn template_id(&self) -> &TE::Id { &self.template_id @@ -218,13 +212,20 @@ impl<TE> Subject<TE> /// /// This trait should not be implemented by hand. pub trait TemplateExt<TE, D> - where TE: TemplateEngine + TemplateEngineCanHandleData<D> +where + TE: TemplateEngine + TemplateEngineCanHandleData<D>, { - - fn render_to_mail_parts<'r>(&self, data: LoadedTemplateData<'r, D>, ctx: &impl Context) - -> Result<(MailParts, Header<headers::Subject>), Error>; - - fn render<'r>(&self, data: LoadedTemplateData<'r, D>, ctx: &impl Context) -> Result<Mail, Error> { + fn render_to_mail_parts<'r>( + &self, + data: LoadedTemplateData<'r, D>, + ctx: &impl Context, + ) -> Result<(MailParts, Header<headers::Subject>), Error>; + + fn render<'r>( + &self, + data: LoadedTemplateData<'r, D>, + ctx: &impl Context, + ) -> Result<Mail, Error> { let (parts, subject) = self.render_to_mail_parts(data, ctx)?; let mut mail = parts.compose(); mail.insert_header(subject); @@ -232,24 +233,24 @@ pub trait TemplateExt<TE, D> } } - impl<TE, D> TemplateExt<TE, D> for Template<TE> - where TE: TemplateEngine + TemplateEngineCanHandleData<D> +where + TE: TemplateEngine + TemplateEngineCanHandleData<D>, { - fn render_to_mail_parts<'r>(&self, data: LoadedTemplateData<'r, D>, ctx: &impl Context) - -> Result<(MailParts, Header<headers::Subject>), Error> - { + fn render_to_mail_parts<'r>( + &self, + data: LoadedTemplateData<'r, D>, + ctx: &impl Context, + ) -> Result<(MailParts, Header<headers::Subject>), Error> { let TemplateData { data, inline_embeddings, - mut attachments + mut attachments, } = data.into(); - let subject = self.engine().render( - self.subject_template_id(), - &data, - AdditionalCIds::new(&[]) - )?; + let subject = + self.engine() + .render(self.subject_template_id(), &data, AdditionalCIds::new(&[]))?; let subject = headers::Subject::auto_body(subject)?; @@ -262,8 +263,8 @@ impl<TE, D> TemplateExt<TE, D> for Template<TE> AdditionalCIds::new(&[ &inline_embeddings, body.inline_embeddings(), - self.inline_embeddings() - ]) + self.inline_embeddings(), + ]), )?; let data = Data::new( @@ -271,19 +272,16 @@ impl<TE, D> TemplateExt<TE, D> for Template<TE> Metadata { file_meta: Default::default(), media_type: body.media_type().clone(), - content_id: ctx.generate_content_id() - } + content_id: ctx.generate_content_id(), + }, ); - let inline_embeddings = body.inline_embeddings() - .values() - .cloned() - .collect(); + let inline_embeddings = body.inline_embeddings().values().cloned().collect(); bodies.push(BodyPart { resource: Resource::Data(data), inline_embeddings, - attachments: Vec::new() + attachments: Vec::new(), }); } @@ -296,13 +294,13 @@ impl<TE, D> TemplateExt<TE, D> for Template<TE> } } - inline_embeddings_vec.extend(inline_embeddings.into_iter().map(|(_,v)|v)); + inline_embeddings_vec.extend(inline_embeddings.into_iter().map(|(_, v)| v)); let parts = MailParts { //UNWRAP_SAFE (complexly mapping a Vec1 is safe) alternative_bodies: Vec1::try_from_vec(bodies).unwrap(), inline_embeddings: inline_embeddings_vec, - attachments + attachments, }; Ok((parts, subject)) @@ -310,18 +308,17 @@ impl<TE, D> TemplateExt<TE, D> for Template<TE> } pub struct TemplateData<'a, D: 'a> { - pub data: MaybeOwned<'a, D>, + pub data: MaybeOwned<'a, D>, pub attachments: Vec<Resource>, - pub inline_embeddings: HashMap<String, Resource> + pub inline_embeddings: HashMap<String, Resource>, } impl<'a, D> TemplateData<'a, D> { - pub fn load(self, ctx: &impl Context) -> DataLoadingFuture<'a, D> { let TemplateData { data, attachments, - inline_embeddings + inline_embeddings, } = self; let loading_fut = Resource::load_container(inline_embeddings, ctx) @@ -329,7 +326,7 @@ impl<'a, D> TemplateData<'a, D> { DataLoadingFuture { payload: Some(data), - loading_fut + loading_fut, } } } @@ -338,7 +335,7 @@ impl<D> From<D> for TemplateData<'static, D> { TemplateData { data: data.into(), attachments: Default::default(), - inline_embeddings: Default::default() + inline_embeddings: Default::default(), } } } @@ -348,7 +345,7 @@ impl<'a, D> From<&'a D> for TemplateData<'a, D> { TemplateData { data: data.into(), attachments: Default::default(), - inline_embeddings: Default::default() + inline_embeddings: Default::default(), } } } @@ -387,8 +384,8 @@ pub struct DataLoadingFuture<'a, D: 'a> { payload: Option<MaybeOwned<'a, D>>, loading_fut: Join< ResourceContainerLoadingFuture<HashMap<String, Resource>>, - ResourceContainerLoadingFuture<Vec<Resource>> - > + ResourceContainerLoadingFuture<Vec<Resource>>, + >, } impl<'a, D> Future for DataLoadingFuture<'a, D> { @@ -396,10 +393,7 @@ impl<'a, D> Future for DataLoadingFuture<'a, D> { type Error = Error; fn poll(&mut self) -> Poll<Self::Item, Self::Error> { - let ( - inline_embeddings, - attachments - ) = try_ready!(self.loading_fut.poll()); + let (inline_embeddings, attachments) = try_ready!(self.loading_fut.poll()); //UNWRAP_SAFE only non if polled after resolved let data = self.payload.take().unwrap(); @@ -407,7 +401,7 @@ impl<'a, D> Future for DataLoadingFuture<'a, D> { let inner = TemplateData { data, inline_embeddings, - attachments + attachments, }; Ok(Async::Ready(LoadedTemplateData(inner))) |