Avoid unstable specialization with this one weird trick! ()

Rustaceans hate him!
This commit is contained in:
Chris Wong 2020-10-05 22:44:27 +13:00 committed by GitHub
parent 165cfd5fe0
commit 49f3c46bd2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 32 additions and 41 deletions

View file

@ -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)

1
benchmarks/Cargo.lock generated
View file

@ -413,7 +413,6 @@ version = "0.22.0"
dependencies = [
"maud_htmlescape",
"maud_macros",
"version_check",
]
[[package]]

1
docs/Cargo.lock generated
View file

@ -295,7 +295,6 @@ version = "0.22.0"
dependencies = [
"maud_htmlescape",
"maud_macros",
"version_check",
]
[[package]]

View file

@ -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"] }

View file

@ -1,5 +0,0 @@
fn main() {
if version_check::is_feature_flaggable() == Some(true) {
println!("cargo:rustc-cfg=unstable");
}
}

View file

@ -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,32 +76,46 @@ 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;
pub trait RenderInternal {
fn __maud_render_to(&self, w: &mut String);
}
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());
}
}
#[cfg(unstable)]
impl Render for String {
fn render_to(&self, w: &mut String) {
let _ = Escaper::new(w).write_str(self);
impl<'a, T: Render + ?Sized> RenderInternal for RenderWrapper<'a, T> {
fn __maud_render_to(&self, w: &mut String) {
self.0.render_to(w);
}
}
#[cfg(unstable)]
impl Render for str {
fn render_to(&self, w: &mut String) {
let _ = Escaper::new(w).write_str(self);
}
}
/// A wrapper that renders the inner value without escaping.

View file

@ -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);
})
}