use std::fmt;
use std::borrow::Cow;
use rocket::{Request, Rocket, Ignite, Sentinel};
use rocket::http::{Status, ContentType};
use rocket::request::{self, FromRequest};
use rocket::serde::Serialize;
use rocket::yansi::Paint;
use crate::{Template, context::ContextManager};
pub struct Metadata<'a>(&'a ContextManager);
impl Metadata<'_> {
pub fn contains_template(&self, name: &str) -> bool {
self.0.context().templates.contains_key(name)
}
pub fn reloading(&self) -> bool {
self.0.is_reloading()
}
pub fn render<S, C>(&self, name: S, context: C) -> Option<(ContentType, String)>
where S: Into<Cow<'static, str>>, C: Serialize
{
Template::render(name.into(), context).finalize(&self.0.context()).ok()
}
}
impl fmt::Debug for Metadata<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_map()
.entries(&self.0.context().templates)
.finish()
}
}
impl Sentinel for Metadata<'_> {
fn abort(rocket: &Rocket<Ignite>) -> bool {
if rocket.state::<ContextManager>().is_none() {
let md = "Metadata".primary().bold();
let fairing = "Template::fairing()".primary().bold();
error!("requested `{}` guard without attaching `{}`.", md, fairing);
info_!("To use or query templates, you must attach `{}`.", fairing);
info_!("See the `Template` documentation for more information.");
return true;
}
false
}
}
#[rocket::async_trait]
impl<'r> FromRequest<'r> for Metadata<'r> {
type Error = ();
async fn from_request(request: &'r Request<'_>) -> request::Outcome<Self, ()> {
request.rocket().state::<ContextManager>()
.map(|cm| request::Outcome::Success(Metadata(cm)))
.unwrap_or_else(|| {
error_!("Uninitialized template context: missing fairing.");
info_!("To use templates, you must attach `Template::fairing()`.");
info_!("See the `Template` documentation for more information.");
request::Outcome::Error((Status::InternalServerError, ()))
})
}
}