Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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: 1 addition & 2 deletions crates/boilerplate-macros/src/implementation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ use super::*;
pub(crate) struct Implementation<'src> {
pub(crate) body: TokenStream,
pub(crate) text: Vec<&'src str>,
pub(crate) tokens: Vec<Token<'src>>,
}

impl<'src> Implementation<'src> {
Expand Down Expand Up @@ -48,6 +47,6 @@ impl<'src> Implementation<'src> {
.parse()
.unwrap();

Self { body, text, tokens }
Self { body, text }
}
}
2 changes: 1 addition & 1 deletion crates/boilerplate-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use {
darling::FromDeriveInput,
new_mime_guess::Mime,
proc_macro2::{Span, TokenStream},
quote::quote,
quote::{quote, ToTokens, TokenStreamExt},
std::path::Path,
syn::{parse_macro_input, DeriveInput, Generics, Ident, LitStr},
};
Expand Down
12 changes: 12 additions & 0 deletions crates/boilerplate-macros/src/source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,15 @@ impl Source {
}
}
}

impl ToTokens for Source {
fn to_tokens(&self, tokens: &mut TokenStream) {
match self {
Self::Literal(literal) => tokens.append(literal.token()),
Self::Path(path) => {
let path = LitStr::new(path, Span::call_site());
tokens.append_all(quote!(include_str!(#path)));
}
}
}
}
48 changes: 5 additions & 43 deletions crates/boilerplate-macros/src/template.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,38 +30,10 @@ impl Template {
let source = &self.source;
let src = source.src();

let Implementation { body, text, tokens } = Implementation::parse(&src, self.escape, false);
let Implementation { body, text } = Implementation::parse(&src, self.escape, false);

let (impl_generics, ty_generics, where_clause) = self.generics.split_for_impl();

let tokens = if cfg!(feature = "reload") {
let tokens = tokens
.into_iter()
.map(|token| match token {
Token::Code { contents } => quote!(::boilerplate::Token::Code { contents: #contents }),
Token::CodeLine { closed, contents } => {
quote!(::boilerplate::Token::CodeLine { closed: #closed, contents: #contents })
}
Token::Interpolation { contents } => {
quote!(::boilerplate::Token::Interpolation { contents: #contents })
}
Token::InterpolationLine { contents, closed } => {
quote!(::boilerplate::Token::InterpolationLine { closed: #closed, contents: #contents })
}
Token::Text { contents, index } => quote!(::boilerplate::Token::Text {
contents: #contents,
index: #index
}),
})
.collect::<Vec<TokenStream>>();

Some(quote! {
const TOKENS: &'static [::boilerplate::Token<'static>] = &[ #(#tokens),* ];
})
} else {
None
};

let path = if cfg!(feature = "reload") {
if let Source::Path(path) = &self.source {
Some(quote!(const PATH: Option<&'static str> = Some(#path);))
Expand All @@ -76,9 +48,9 @@ impl Template {

quote! {
impl #impl_generics ::boilerplate::Boilerplate for #ident #ty_generics #where_clause {
const TEXT: &'static [&'static str] = &[ #(#text),* ];
const TEMPLATE: &'static str = #source;

#tokens
const TEXT: &'static [&'static str] = &[ #(#text),* ];

#path

Expand Down Expand Up @@ -132,16 +104,6 @@ mod tests {

#[test]
fn display_impl() {
let tokens = if cfg!(feature = "reload") {
Some(quote! {
const TOKENS: &'static [::boilerplate::Token<'static>] = &[
::boilerplate::Token::Text { contents: "", index: 0usize }
];
})
} else {
None
};

let path = if cfg!(feature = "reload") {
Some(quote!(
const PATH: Option<&'static str> = None;
Expand Down Expand Up @@ -175,9 +137,9 @@ mod tests {
.to_string(),
quote!(
impl ::boilerplate::Boilerplate for Foo {
const TEXT: &'static [&'static str] = &[#text];
const TEMPLATE: &'static str = "";

#tokens
const TEXT: &'static [&'static str] = &[#text];

#path

Expand Down
26 changes: 13 additions & 13 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -703,15 +703,14 @@ mod reload;
/// The boilerplate trait, automatically implemented by the `Boilerplate`
/// derive macro.
pub trait Boilerplate {
/// The original template.
const TEMPLATE: &'static str;

/// The parsed template's text blocks.
const TEXT: &'static [&'static str];

#[cfg(feature = "reload")]
/// The parsed template's tokens.
const TOKENS: &'static [Token<'static>];

#[cfg(feature = "reload")]
/// Path to the original template file.
#[cfg(feature = "reload")]
const PATH: Option<&'static str>;

/// Render the template.
Expand All @@ -724,7 +723,6 @@ pub trait Boilerplate {
boilerplate_output: &mut Formatter,
) -> fmt::Result;

#[cfg(feature = "reload")]
/// Reload the template from a new template string.
///
/// The new template must be compatible with the original template. Templates
Expand All @@ -733,17 +731,19 @@ pub trait Boilerplate {
/// contain literal text, may be different.
///
/// - `src` - The new template source text.
#[cfg(feature = "reload")]
fn reload(&self, src: &str) -> Result<Reload<&Self>, Error> {
let tokens = Token::parse(src).map_err(Error::Parse)?;
let new = Token::parse(src).map_err(Error::ParseNew)?;
let old = Token::parse(Self::TEMPLATE).map_err(Error::ParseOld)?;

if tokens.len() != Self::TOKENS.len() {
if new.len() != old.len() {
return Err(Error::Length {
new: tokens.len(),
old: Self::TOKENS.len(),
new: new.len(),
old: old.len(),
});
}

for (new, old) in tokens.iter().copied().zip(Self::TOKENS.iter().copied()) {
for (new, old) in new.iter().zip(old) {
if !new.is_compatible_with(old) {
return Err(Error::Incompatible {
new: new.to_string(),
Expand All @@ -754,17 +754,17 @@ pub trait Boilerplate {

Ok(Reload {
inner: self,
text: tokens
text: new
.into_iter()
.filter_map(Token::text)
.map(ToOwned::to_owned)
.collect(),
})
}

#[cfg(feature = "reload")]
/// Reload the template from its original path. Cannot be used on templates
/// created from string literals.
#[cfg(feature = "reload")]
fn reload_from_path(&self) -> Result<Reload<&Self>, Error> {
let Some(path) = Self::PATH else {
return Err(Error::Path);
Expand Down
7 changes: 5 additions & 2 deletions src/reload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ pub enum Error {
/// New template does not have the same number of blocks.
Length { new: usize, old: usize },
/// Failed to parse new template.
Parse(boilerplate_parser::Error),
ParseNew(boilerplate_parser::Error),
/// Failed to parse old template.
ParseOld(boilerplate_parser::Error),
/// Template has no path
Path,
}
Expand All @@ -44,7 +46,8 @@ impl Display for Error {
f,
"new template has {new} blocks but old template has {old} blocks",
),
Self::Parse(err) => write!(f, "failed to parse new template: {err}"),
Self::ParseNew(err) => write!(f, "failed to parse new template: {err}"),
Self::ParseOld(err) => write!(f, "failed to parse old template: {err}"),
Self::Path => write!(f, "template has no path"),
}
}
Expand Down
Loading