Render with Display using autoref specialization (#359)
This commit is contained in:
parent
81ace856a4
commit
6cdf12b427
3 changed files with 99 additions and 1 deletions
|
@ -340,3 +340,54 @@ mod axum_support {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub mod macro_private {
|
||||||
|
use crate::{display, Render};
|
||||||
|
use alloc::string::String;
|
||||||
|
use core::fmt::Display;
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! render_to {
|
||||||
|
($x:expr, $buffer:expr) => {{
|
||||||
|
use $crate::macro_private::*;
|
||||||
|
match ChooseRenderOrDisplay($x) {
|
||||||
|
x => (&&x).implements_render_or_display().render_to(x.0, $buffer),
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub use render_to;
|
||||||
|
|
||||||
|
pub struct ChooseRenderOrDisplay<T>(pub T);
|
||||||
|
|
||||||
|
pub struct ViaRenderTag;
|
||||||
|
pub struct ViaDisplayTag;
|
||||||
|
|
||||||
|
pub trait ViaRender {
|
||||||
|
fn implements_render_or_display(&self) -> ViaRenderTag {
|
||||||
|
ViaRenderTag
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub trait ViaDisplay {
|
||||||
|
fn implements_render_or_display(&self) -> ViaDisplayTag {
|
||||||
|
ViaDisplayTag
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Render> ViaRender for &ChooseRenderOrDisplay<T> {}
|
||||||
|
impl<T: Display> ViaDisplay for ChooseRenderOrDisplay<T> {}
|
||||||
|
|
||||||
|
impl ViaRenderTag {
|
||||||
|
pub fn render_to<T: Render + ?Sized>(self, value: &T, buffer: &mut String) {
|
||||||
|
value.render_to(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ViaDisplayTag {
|
||||||
|
pub fn render_to<T: Display + ?Sized>(self, value: &T, buffer: &mut String) {
|
||||||
|
display(value).render_to(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -83,3 +83,50 @@ fn issue_97() {
|
||||||
|
|
||||||
assert_eq!(html! { (Pinkie) }.into_string(), "42");
|
assert_eq!(html! { (Pinkie) }.into_string(), "42");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn only_display() {
|
||||||
|
use core::fmt::Display;
|
||||||
|
|
||||||
|
struct OnlyDisplay;
|
||||||
|
impl Display for OnlyDisplay {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "<hello>")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(html! { (OnlyDisplay) }.into_string(), "<hello>");
|
||||||
|
assert_eq!(html! { (&OnlyDisplay) }.into_string(), "<hello>");
|
||||||
|
assert_eq!(html! { (&&OnlyDisplay) }.into_string(), "<hello>");
|
||||||
|
assert_eq!(html! { (&&&OnlyDisplay) }.into_string(), "<hello>");
|
||||||
|
assert_eq!(html! { (&&&&OnlyDisplay) }.into_string(), "<hello>");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn prefer_render_over_display() {
|
||||||
|
use core::fmt::Display;
|
||||||
|
use maud::Render;
|
||||||
|
|
||||||
|
struct RenderAndDisplay;
|
||||||
|
impl Display for RenderAndDisplay {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "<display>")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Render for RenderAndDisplay {
|
||||||
|
fn render_to(&self, buffer: &mut String) {
|
||||||
|
buffer.push_str("<render>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(html! { (RenderAndDisplay) }.into_string(), "<render>");
|
||||||
|
assert_eq!(html! { (&RenderAndDisplay) }.into_string(), "<render>");
|
||||||
|
assert_eq!(html! { (&&RenderAndDisplay) }.into_string(), "<render>");
|
||||||
|
assert_eq!(html! { (&&&RenderAndDisplay) }.into_string(), "<render>");
|
||||||
|
assert_eq!(html! { (&&&&RenderAndDisplay) }.into_string(), "<render>");
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
html! { (maud::display(RenderAndDisplay)) }.into_string(),
|
||||||
|
"<display>"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -103,7 +103,7 @@ impl Generator {
|
||||||
|
|
||||||
fn splice(&self, expr: TokenStream, build: &mut Builder) {
|
fn splice(&self, expr: TokenStream, build: &mut Builder) {
|
||||||
let output_ident = self.output_ident.clone();
|
let output_ident = self.output_ident.clone();
|
||||||
build.push_tokens(quote!(maud::Render::render_to(&#expr, &mut #output_ident);));
|
build.push_tokens(quote!(maud::macro_private::render_to!(&#expr, &mut #output_ident);));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn element(&self, name: TokenStream, attrs: Vec<Attr>, body: ElementBody, build: &mut Builder) {
|
fn element(&self, name: TokenStream, attrs: Vec<Attr>, body: ElementBody, build: &mut Builder) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue