1#![cfg_attr(finchers_inject_extern_prelude, feature(extern_prelude))]
3
4#![doc(html_root_url = "https://docs.rs/finchers-template/0.1.1")]
7#![warn(
8 missing_docs,
9 missing_debug_implementations,
10 nonstandard_style,
11 rust_2018_idioms,
12 unused,
13)]
14#![cfg_attr(finchers_deny_warnings, deny(warnings))]
16#![cfg_attr(finchers_deny_warnings, doc(test(attr(deny(warnings)))))]
17
18extern crate failure;
19extern crate finchers;
20#[macro_use]
21extern crate futures;
22extern crate http;
23extern crate mime;
24extern crate mime_guess;
25extern crate serde;
26
27#[cfg(feature = "handlebars")]
28extern crate handlebars;
29
30#[cfg(feature = "tera")]
31extern crate tera;
32
33#[allow(deprecated)]
34pub use self::imp::TemplateEndpoint;
35pub use self::imp::{renderer, RenderEndpoint, Renderer, TemplateEngine};
36
37#[cfg(feature = "handlebars")]
38#[doc(no_inline)]
39pub use handlebars::Handlebars;
40
41#[cfg(feature = "tera")]
42#[doc(no_inline)]
43pub use tera::Tera;
44
45#[cfg(feature = "askama")]
46pub mod askama;
47
48#[cfg(feature = "horrorshow")]
49pub mod horrorshow;
50
51mod imp {
52 use finchers;
53 use finchers::endpoint;
54 use finchers::endpoint::wrapper::Wrapper;
55 use finchers::endpoint::{ApplyContext, ApplyResult, Endpoint, IntoEndpoint};
56 use finchers::error::Error;
57 use finchers::output::body::ResBody;
58
59 #[cfg(feature = "handlebars")]
60 use handlebars::Handlebars;
61 #[cfg(feature = "tera")]
62 use tera::Tera;
63
64 use failure::SyncFailure;
65 use futures::{Future, Poll};
66 use http::header;
67 use http::header::HeaderValue;
68 use http::Response;
69 use mime::Mime;
70 use mime_guess::guess_mime_type;
71 use serde::Serialize;
72
73 use std::borrow::Cow;
74 use std::rc::Rc;
75 use std::sync::Arc;
76
77 #[allow(missing_docs)]
79 pub trait TemplateEngine {
80 type Body: ResBody;
81 type Error: Into<Error>;
82
83 fn render<T>(&self, template_name: &str, ctx: &T) -> Result<Self::Body, Self::Error>
84 where
85 T: Serialize;
86 }
87
88 impl<E: TemplateEngine> TemplateEngine for Box<E> {
89 type Body = E::Body;
90 type Error = E::Error;
91
92 fn render<T>(&self, template_name: &str, ctx: &T) -> Result<Self::Body, Self::Error>
93 where
94 T: Serialize,
95 {
96 (**self).render(template_name, ctx)
97 }
98 }
99
100 impl<E: TemplateEngine> TemplateEngine for Rc<E> {
101 type Body = E::Body;
102 type Error = E::Error;
103
104 fn render<T>(&self, template_name: &str, ctx: &T) -> Result<Self::Body, Self::Error>
105 where
106 T: Serialize,
107 {
108 (**self).render(template_name, ctx)
109 }
110 }
111
112 impl<E: TemplateEngine> TemplateEngine for Arc<E> {
113 type Body = E::Body;
114 type Error = E::Error;
115
116 fn render<T>(&self, template_name: &str, ctx: &T) -> Result<Self::Body, Self::Error>
117 where
118 T: Serialize,
119 {
120 (**self).render(template_name, ctx)
121 }
122 }
123
124 #[cfg(feature = "handlebars")]
125 impl TemplateEngine for Handlebars {
126 type Body = String;
127 type Error = Error;
128
129 fn render<T>(&self, template_name: &str, ctx: &T) -> Result<Self::Body, Self::Error>
130 where
131 T: Serialize,
132 {
133 Handlebars::render(self, template_name, ctx)
134 .map_err(|err| finchers::error::fail(SyncFailure::new(err)))
135 }
136 }
137
138 #[cfg(feature = "tera")]
139 impl TemplateEngine for Tera {
140 type Body = String;
141 type Error = Error;
142
143 fn render<T>(&self, template_name: &str, ctx: &T) -> Result<Self::Body, Self::Error>
144 where
145 T: Serialize,
146 {
147 Tera::render(self, template_name, ctx)
148 .map_err(|err| finchers::error::fail(SyncFailure::new(err)))
149 }
150 }
151
152 pub fn renderer<T>(engine: T, name: impl Into<Cow<'static, str>>) -> Renderer<T>
154 where
155 T: TemplateEngine,
156 {
157 let name = name.into();
158 let content_type = HeaderValue::from_shared(guess_mime_type(&*name).as_ref().into())
159 .expect("should be a valid header value");
160 Renderer {
161 engine,
162 name,
163 content_type,
164 }
165 }
166
167 #[derive(Debug, Clone)]
169 pub struct Renderer<T> {
170 engine: T,
171 name: Cow<'static, str>,
172 content_type: HeaderValue,
173 }
174
175 impl<T> Renderer<T>
176 where
177 T: TemplateEngine,
178 {
179 #[doc(hidden)]
180 #[deprecated(note = "use `renderer()` instead.")]
181 pub fn new(engine: T, name: impl Into<Cow<'static, str>>) -> Renderer<T> {
182 renderer(engine, name)
183 }
184
185 pub fn content_type(self, content_type: Mime) -> Renderer<T> {
189 Renderer {
190 content_type: HeaderValue::from_shared(content_type.as_ref().into())
191 .expect("should be a valid header value"),
192 ..self
193 }
194 }
195
196 fn render_response<CtxT>(&self, ctx: &CtxT) -> Result<Response<T::Body>, Error>
198 where
199 CtxT: Serialize,
200 {
201 let mut response = self
202 .engine
203 .render(&self.name, ctx)
204 .map(Response::new)
205 .map_err(Into::into)?;
206 response
207 .headers_mut()
208 .insert(header::CONTENT_TYPE, self.content_type.clone());
209 Ok(response)
210 }
211 }
212
213 impl<'a, T> IntoEndpoint<'a> for Renderer<T>
214 where
215 T: TemplateEngine + 'a,
216 {
217 type Output = (Response<T::Body>,);
218 type Endpoint = RenderEndpoint<T, endpoint::Cloned<self::dummy::DummyContext>>;
219
220 fn into_endpoint(self) -> Self::Endpoint {
221 RenderEndpoint {
222 renderer: self,
223 endpoint: endpoint::cloned(Default::default()),
224 }
225 }
226 }
227
228 mod dummy {
229 use serde::ser::{Serialize, SerializeMap, Serializer};
230
231 #[derive(Debug, Default, Clone, Copy)]
232 pub struct DummyContext {
233 _priv: (),
234 }
235
236 impl Serialize for DummyContext {
237 fn serialize<S>(&self, ser: S) -> Result<S::Ok, S::Error>
238 where
239 S: Serializer,
240 {
241 ser.serialize_map(Some(0))?.end()
242 }
243 }
244 }
245
246 impl<'a, T, E, CtxT> Wrapper<'a, E> for Renderer<T>
247 where
248 T: TemplateEngine + 'a,
249 E: Endpoint<'a, Output = (CtxT,)>,
250 CtxT: Serialize,
251 {
252 type Output = (Response<T::Body>,);
253 type Endpoint = RenderEndpoint<T, E>;
254
255 fn wrap(self, endpoint: E) -> Self::Endpoint {
256 RenderEndpoint {
257 renderer: self,
258 endpoint,
259 }
260 }
261 }
262
263 #[doc(hidden)]
264 #[deprecated(since = "0.1.1", note = "renamed to `RenderEndpoint<T, E>")]
265 pub type TemplateEndpoint<T, E> = RenderEndpoint<T, E>;
266
267 #[derive(Debug)]
269 pub struct RenderEndpoint<T, E> {
270 renderer: Renderer<T>,
271 endpoint: E,
272 }
273
274 impl<'a, T, E, CtxT> Endpoint<'a> for RenderEndpoint<T, E>
275 where
276 T: TemplateEngine + 'a,
277 E: Endpoint<'a, Output = (CtxT,)>,
278 CtxT: Serialize,
279 {
280 type Output = (Response<T::Body>,);
281 type Future = TemplateFuture<'a, T, E>;
282
283 #[inline]
284 fn apply(&'a self, cx: &mut ApplyContext<'_>) -> ApplyResult<Self::Future> {
285 Ok(TemplateFuture {
286 future: self.endpoint.apply(cx)?,
287 renderer: &self.renderer,
288 })
289 }
290 }
291
292 #[derive(Debug)]
293 pub struct TemplateFuture<'a, T: TemplateEngine + 'a, E: Endpoint<'a>> {
294 future: E::Future,
295 renderer: &'a Renderer<T>,
296 }
297
298 impl<'a, T, E, CtxT> Future for TemplateFuture<'a, T, E>
299 where
300 T: TemplateEngine + 'a,
301 E: Endpoint<'a, Output = (CtxT,)>,
302 CtxT: Serialize,
303 {
304 type Item = (Response<T::Body>,);
305 type Error = Error;
306
307 #[inline]
308 fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
309 let (ctx,) = try_ready!(self.future.poll());
310 self.renderer
311 .render_response(&ctx)
312 .map(|response| (response,).into())
313 }
314 }
315}