diff --git a/.travis.yml b/.travis.yml index c7e4953..1c6e928 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,11 +18,6 @@ jobs: done (exit $CLIPPY_STATUS) fi - - name: "Stable" - rust: stable - script: - # Skip `--all-features` because stable Rocket isn't released yet - - cargo test --workspace - name: "Benchmarks" script: - (cd benchmarks && cargo test --benches --locked) diff --git a/benchmarks/Cargo.lock b/benchmarks/Cargo.lock index 7d802bb..4d5cd97 100644 --- a/benchmarks/Cargo.lock +++ b/benchmarks/Cargo.lock @@ -413,7 +413,6 @@ version = "0.22.0" dependencies = [ "maud_htmlescape", "maud_macros", - "version_check", ] [[package]] diff --git a/docs/Cargo.lock b/docs/Cargo.lock index f954bf7..1218e8b 100644 --- a/docs/Cargo.lock +++ b/docs/Cargo.lock @@ -295,7 +295,6 @@ version = "0.22.0" dependencies = [ "maud_htmlescape", "maud_macros", - "version_check", ] [[package]] diff --git a/maud/Cargo.toml b/maud/Cargo.toml index 3a6a49e..a80e3d0 100644 --- a/maud/Cargo.toml +++ b/maud/Cargo.toml @@ -25,9 +25,6 @@ rocket = { version = ">= 0.3, < 0.5", optional = true } futures = { version = "0.3.0", optional = true } actix-web-dep = { version = "2.0.0", optional = true, default-features = false, package = "actix-web" } -[build-dependencies] -version_check = "0.9.2" - [dev-dependencies] trybuild = { version = "1.0.33", features = ["diff"] } diff --git a/maud/build.rs b/maud/build.rs deleted file mode 100644 index cf8eb1d..0000000 --- a/maud/build.rs +++ /dev/null @@ -1,5 +0,0 @@ -fn main() { - if version_check::is_feature_flaggable() == Some(true) { - println!("cargo:rustc-cfg=unstable"); - } -} diff --git a/maud/src/lib.rs b/maud/src/lib.rs index 9100587..e1bb924 100644 --- a/maud/src/lib.rs +++ b/maud/src/lib.rs @@ -1,5 +1,3 @@ -#![cfg_attr(unstable, feature(min_specialization))] - //! A macro for writing HTML templates. //! //! This documentation only describes the runtime API. For a general @@ -78,31 +76,45 @@ pub trait Render { } } -#[cfg(not(unstable))] impl<T: fmt::Display + ?Sized> Render for T { fn render_to(&self, w: &mut String) { let _ = write!(Escaper::new(w), "{}", self); } } -#[cfg(unstable)] -impl<T: fmt::Display + ?Sized> Render for T { - default fn render_to(&self, w: &mut String) { - let _ = write!(Escaper::new(w), "{}", self); - } -} +/// Spicy hack to specialize `Render` for `T: AsRef<str>`. +/// +/// The `std::fmt` machinery is rather heavyweight, both in code size and speed. +/// It would be nice to skip this overhead for the common cases of `&str` and +/// `String`. But the obvious solution uses *specialization*, which (as of this +/// writing) requires Nightly. The [*inherent method specialization*][1] trick +/// is less clear but works on Stable. +/// +/// This module is an implementation detail and should not be used directly. +/// +/// [1]: https://github.com/dtolnay/case-studies/issues/14 +#[doc(hidden)] +pub mod render { + use crate::Render; + use maud_htmlescape::Escaper; + use std::fmt::Write; -#[cfg(unstable)] -impl Render for String { - fn render_to(&self, w: &mut String) { - let _ = Escaper::new(w).write_str(self); + pub trait RenderInternal { + fn __maud_render_to(&self, w: &mut String); } -} -#[cfg(unstable)] -impl Render for str { - fn render_to(&self, w: &mut String) { - let _ = Escaper::new(w).write_str(self); + pub struct RenderWrapper<'a, T: ?Sized>(pub &'a T); + + impl<'a, T: AsRef<str> + ?Sized> RenderWrapper<'a, T> { + pub fn __maud_render_to(&self, w: &mut String) { + let _ = Escaper::new(w).write_str(self.0.as_ref()); + } + } + + impl<'a, T: Render + ?Sized> RenderInternal for RenderWrapper<'a, T> { + fn __maud_render_to(&self, w: &mut String) { + self.0.render_to(w); + } } } diff --git a/maud_macros/src/generate.rs b/maud_macros/src/generate.rs index 976ad98..d3337fc 100644 --- a/maud_macros/src/generate.rs +++ b/maud_macros/src/generate.rs @@ -91,14 +91,8 @@ impl Generator { fn splice(&self, expr: TokenStream) -> TokenStream { let output_ident = self.output_ident.clone(); quote!({ - // Create a local trait alias so that autoref works - trait Render: maud::Render { - fn __maud_render_to(&self, output_ident: &mut ::std::string::String) { - maud::Render::render_to(self, output_ident); - } - } - impl<T: maud::Render> Render for T {} - #expr.__maud_render_to(&mut #output_ident); + use maud::render::{RenderInternal, RenderWrapper}; + RenderWrapper(&#expr).__maud_render_to(&mut #output_ident); }) }