Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove syn and proc-macro2 and quote dependencies from askama_derive #953

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions askama_derive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,5 @@ with-warp = []
parser = { package = "askama_parser", version = "0.2", path = "../askama_parser" }
mime = "0.3"
mime_guess = "2"
proc-macro2 = "1"
quote = "1"
serde = { version = "1.0", optional = true, features = ["derive"] }
syn = "2"
basic-toml = { version = "0.1.1", optional = true }
218 changes: 88 additions & 130 deletions askama_derive/src/generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ use parser::node::{
Call, Comment, CondTest, If, Include, Let, Lit, Loop, Match, Target, Whitespace, Ws,
};
use parser::{Expr, Node};
use quote::quote;

pub(crate) struct Generator<'a> {
// The template input state: original struct AST and attributes
Expand Down Expand Up @@ -105,12 +104,7 @@ impl<'a> Generator<'a> {
};
if path_is_valid {
let path = path.to_str().unwrap();
buf.writeln(
&quote! {
include_bytes!(#path);
}
.to_string(),
)?;
buf.writeln(&format!("include_bytes!({path:?});"))?;
}
}

Expand Down Expand Up @@ -196,112 +190,72 @@ impl<'a> Generator<'a> {
// Implement `From<Template> for hyper::Response<Body>` and `From<Template> for hyper::Body.
#[cfg(feature = "with-hyper")]
fn impl_hyper_into_response(&mut self, buf: &mut Buffer) -> Result<(), CompileError> {
let (impl_generics, orig_ty_generics, where_clause) =
self.input.ast.generics.split_for_impl();
let ident = &self.input.ast.ident;
// From<Template> for hyper::Response<Body>
buf.writeln(&format!(
"{} {{",
quote!(
impl #impl_generics ::core::convert::From<&#ident #orig_ty_generics>
for ::askama_hyper::hyper::Response<::askama_hyper::hyper::Body>
#where_clause
)
))?;
buf.writeln("#[inline]")?;
buf.writeln(&format!(
"{} {{",
quote!(fn from(value: &#ident #orig_ty_generics) -> Self)
))?;
buf.writeln("::askama_hyper::respond(value)")?;
buf.writeln("}")?;
buf.writeln("}")?;
let generics_with_bounds = self.input.ast.generics.display_with_bounds();
let orig_ty_generics = &self.input.ast.generics;
let type_name = &self.input.ast.ident;
let where_clause = &self.input.ast.where_clause;

// TryFrom<Template> for hyper::Body
buf.writeln(&format!(
"{} {{",
quote!(
impl #impl_generics ::core::convert::TryFrom<&#ident #orig_ty_generics>
for ::askama_hyper::hyper::Body
#where_clause
)
))?;
buf.writeln("type Error = ::askama::Error;")?;
buf.writeln("#[inline]")?;
// From<Template> for hyper::Response<Body>
buf.writeln(&format!(
"{} {{",
quote!(fn try_from(value: &#ident #orig_ty_generics) -> Result<Self, Self::Error>)
))?;
buf.writeln("::askama::Template::render(value).map(Into::into)")?;
buf.writeln("}")?;
buf.writeln("}")
"\
impl {generics_with_bounds} ::core::convert::From<&{type_name} {orig_ty_generics}>
for ::askama_hyper::hyper::Response<::askama_hyper::hyper::Body>
{where_clause}
{{
#[inline]
fn from(value: &{type_name} {orig_ty_generics}) -> Self {{
::askama_hyper::respond(value)
}}
}}

impl {generics_with_bounds} ::core::convert::TryFrom<&{type_name} {orig_ty_generics}>
for ::askama_hyper::hyper::Body
{where_clause}
{{
type Error = ::askama::Error;

#[inline]
fn try_from(value: &{type_name} {orig_ty_generics}) -> Result<Self, Self::Error> {{
::askama::Template::render(value).map(Into::into)
}}
}}"
))
}

// Implement mendes' `Responder`.
#[cfg(feature = "with-mendes")]
fn impl_mendes_responder(&mut self, buf: &mut Buffer) -> Result<(), CompileError> {
let param = syn::parse_str("A: ::mendes::Application").unwrap();

let mut generics = self.input.ast.generics.clone();
generics.params.push(param);
let (_, orig_ty_generics, _) = self.input.ast.generics.split_for_impl();
let (impl_generics, _, where_clause) = generics.split_for_impl();

let mut where_clause = match where_clause {
Some(clause) => clause.clone(),
None => syn::WhereClause {
where_token: syn::Token![where](proc_macro2::Span::call_site()),
predicates: syn::punctuated::Punctuated::new(),
},
};
generics.add_generic("A", "::mendes::Application");

where_clause
.predicates
.push(syn::parse_str("A::ResponseBody: From<String>").unwrap());
where_clause
.predicates
.push(syn::parse_str("A::Error: From<::askama_mendes::Error>").unwrap());
let generics_with_bounds = generics.display_with_bounds();
let orig_ty_generics = &self.input.ast.generics;
let type_name = &self.input.ast.ident;
let mut where_clause = self.input.ast.where_clause.clone();

buf.writeln(
format!(
"{} {} for {} {} {{",
quote!(impl #impl_generics),
"::mendes::application::IntoResponse<A>",
self.input.ast.ident,
quote!(#orig_ty_generics #where_clause),
)
.as_ref(),
)?;

buf.writeln(
"fn into_response(self, app: &A, req: &::mendes::http::request::Parts) \
-> ::mendes::http::Response<A::ResponseBody> {",
)?;
where_clause.add_predicate("A::ResponseBody: From<String>");
where_clause.add_predicate("A::Error: From<::askama_mendes::Error>");

buf.writeln("::askama_mendes::into_response(app, req, &self)")?;
buf.writeln("}")?;
buf.writeln("}")?;
buf.writeln(&format!(
"\
impl {generics_with_bounds} ::mendes::application::IntoResponse<A> for {type_name} {orig_ty_generics}
{where_clause} {{
fn into_response(self, app: &A, req: &::mendes::http::request::Parts) \
-> ::mendes::http::Response<A::ResponseBody> {{
::askama_mendes::into_response(app, req, &self)
}}
}}",
))?;
Ok(())
}

// Implement Rocket's `Responder`.
#[cfg(feature = "with-rocket")]
fn impl_rocket_responder(&mut self, buf: &mut Buffer) -> Result<(), CompileError> {
let lifetime1 = syn::Lifetime::new("'askama1", proc_macro2::Span::call_site());
let lifetime2 = syn::Lifetime::new("'askama2", proc_macro2::Span::call_site());

let mut param2 = syn::LifetimeParam::new(lifetime2);
param2.colon_token = Some(syn::Token![:](proc_macro2::Span::call_site()));
param2.bounds = syn::punctuated::Punctuated::new();
param2.bounds.push_value(lifetime1.clone());

let param1 = syn::GenericParam::Lifetime(syn::LifetimeParam::new(lifetime1));
let param2 = syn::GenericParam::Lifetime(param2);

self.write_header(
buf,
"::askama_rocket::Responder<'askama1, 'askama2>",
Some(vec![param1, param2]),
Some(&[("'askama1", ""), ("'askama2", "'askama1")]),
)?;

buf.writeln("#[inline]")?;
Expand All @@ -324,30 +278,39 @@ impl<'a> Generator<'a> {
None,
)?;
buf.writeln(
"type Error = ::askama_tide::askama::Error;\n\
#[inline]\n\
fn try_into(self) -> ::askama_tide::askama::Result<::askama_tide::tide::Body> {",
"\
type Error = ::askama_tide::askama::Error;

#[inline]
fn try_into(self) -> ::askama_tide::askama::Result<::askama_tide::tide::Body> {
::askama_tide::try_into_body(&self)
}
}",
)?;
buf.writeln("::askama_tide::try_into_body(&self)")?;
buf.writeln("}")?;
buf.writeln("}")?;

buf.writeln("#[allow(clippy::from_over_into)]")?;
self.write_header(buf, "Into<::askama_tide::tide::Response>", None)?;
buf.writeln("#[inline]")?;
buf.writeln("fn into(self) -> ::askama_tide::tide::Response {")?;
buf.writeln("::askama_tide::into_response(&self)")?;
buf.writeln("}\n}")
buf.writeln(
"\
#[inline]
fn into(self) -> ::askama_tide::tide::Response {
::askama_tide::into_response(&self)
}
}",
)
}

#[cfg(feature = "with-warp")]
fn impl_warp_reply(&mut self, buf: &mut Buffer) -> Result<(), CompileError> {
self.write_header(buf, "::askama_warp::warp::reply::Reply", None)?;
buf.writeln("#[inline]")?;
buf.writeln("fn into_response(self) -> ::askama_warp::warp::reply::Response {")?;
buf.writeln("::askama_warp::reply(&self)")?;
buf.writeln("}")?;
buf.writeln("}")
buf.writeln(
"\
#[inline]
fn into_response(self) -> ::askama_warp::warp::reply::Response {
::askama_warp::reply(&self)
}
}",
)
}

// Writes header for the `impl` for `TraitFromPathName` or `Template`
Expand All @@ -356,25 +319,25 @@ impl<'a> Generator<'a> {
&mut self,
buf: &mut Buffer,
target: &str,
params: Option<Vec<syn::GenericParam>>,
lifetimes: Option<&[(&str, &str)]>,
) -> Result<(), CompileError> {
let mut generics = self.input.ast.generics.clone();
if let Some(params) = params {
for param in params {
generics.params.push(param);
let mut generics;
let generics = if let Some(lifetimes) = lifetimes {
generics = self.input.ast.generics.clone();
for (lifetime, bound) in lifetimes {
generics.add_lifetime(lifetime, bound);
}
}
let (_, orig_ty_generics, _) = self.input.ast.generics.split_for_impl();
let (impl_generics, _, where_clause) = generics.split_for_impl();
&generics
} else {
&self.input.ast.generics
};
let generics_with_bounds = generics.display_with_bounds();
let orig_ty_generics = &self.input.ast.generics;
let type_name = &self.input.ast.ident;
let where_clause = &self.input.ast.where_clause;
buf.writeln(
format!(
"{} {} for {}{} {{",
quote!(impl #impl_generics),
target,
self.input.ast.ident,
quote!(#orig_ty_generics #where_clause),
)
.as_ref(),
format!("impl{generics_with_bounds} {target} for {type_name}{orig_ty_generics} {where_clause} {{")
.as_ref(),
)
}

Expand Down Expand Up @@ -835,12 +798,7 @@ impl<'a> Generator<'a> {
// Make sure the compiler understands that the generated code depends on the template file.
{
let path = path.to_str().unwrap();
buf.writeln(
&quote! {
include_bytes!(#path);
}
.to_string(),
)?;
buf.writeln(&format!("include_bytes!({path:?});"))?;
}

// We clone the context of the child in order to preserve their macros and imports.
Expand Down
Loading