From 4978b998fe3b421cb26b403e75a01d847895310e Mon Sep 17 00:00:00 2001 From: Tim Kurdov Date: Sat, 12 Oct 2024 13:30:13 +0100 Subject: [PATCH] Allow boolean & update error for byte literals in `html!` (#3441) * made byte & boolean literals accepted by html * improved error message, outruled byte-string to HTML conversion * update tests --- packages/yew-macro/src/html_tree/html_node.rs | 16 +++++++++--- packages/yew-macro/src/stringify.rs | 26 ++++++++++++------- .../tests/html_macro/node-fail.stderr | 18 +++---------- .../yew-macro/tests/html_macro/node-pass.rs | 8 +++--- 4 files changed, 37 insertions(+), 31 deletions(-) diff --git a/packages/yew-macro/src/html_tree/html_node.rs b/packages/yew-macro/src/html_tree/html_node.rs index 6b8022ba11a..06be31ccc46 100644 --- a/packages/yew-macro/src/html_tree/html_node.rs +++ b/packages/yew-macro/src/html_tree/html_node.rs @@ -17,9 +17,19 @@ pub enum HtmlNode { impl Parse for HtmlNode { fn parse(input: ParseStream) -> Result { let node = if HtmlNode::peek(input.cursor()).is_some() { - let lit: Lit = input.parse()?; - if matches!(lit, Lit::ByteStr(_) | Lit::Byte(_) | Lit::Verbatim(_)) { - return Err(syn::Error::new(lit.span(), "unsupported type")); + let lit = input.parse()?; + match lit { + Lit::ByteStr(lit) => { + return Err(syn::Error::new( + lit.span(), + "byte-strings can't be converted to HTML text + note: remove the `b` prefix or convert this to a `String`", + )) + } + Lit::Verbatim(lit) => { + return Err(syn::Error::new(lit.span(), "unsupported literal")) + } + _ => (), } HtmlNode::Literal(Box::new(lit)) } else { diff --git a/packages/yew-macro/src/stringify.rs b/packages/yew-macro/src/stringify.rs index 4ea9d6483c4..75764266841 100644 --- a/packages/yew-macro/src/stringify.rs +++ b/packages/yew-macro/src/stringify.rs @@ -1,3 +1,6 @@ +use std::borrow::Cow; +use std::mem::size_of; + use proc_macro2::{Span, TokenStream}; use quote::{quote_spanned, ToTokens}; use syn::spanned::Spanned; @@ -75,15 +78,19 @@ impl Stringify for LitStr { } } } + impl Stringify for Lit { fn try_into_lit(&self) -> Option { - let s = match self { + let mut buf = [0; size_of::()]; + let s: Cow<'_, str> = match self { Lit::Str(v) => return v.try_into_lit(), - Lit::Char(v) => v.value().to_string(), - Lit::Int(v) => v.base10_digits().to_string(), - Lit::Float(v) => v.base10_digits().to_string(), - Lit::Bool(_) | Lit::ByteStr(_) | Lit::Byte(_) | Lit::Verbatim(_) => return None, - _ => unreachable!("unknown Lit"), + Lit::Char(v) => (&*v.value().encode_utf8(&mut buf)).into(), + Lit::Int(v) => v.base10_digits().into(), + Lit::Float(v) => v.base10_digits().into(), + Lit::Bool(v) => if v.value() { "true" } else { "false" }.into(), + Lit::Byte(v) => v.value().to_string().into(), + Lit::Verbatim(_) | Lit::ByteStr(_) => return None, + _ => unreachable!("unknown Lit {:?}", self), }; Some(LitStr::new(&s, self.span())) } @@ -91,10 +98,10 @@ impl Stringify for Lit { fn stringify(&self) -> TokenStream { self.try_into_lit() .as_ref() - .map(Stringify::stringify) - .unwrap_or_else(|| stringify_at_runtime(self)) + .map_or_else(|| stringify_at_runtime(self), Stringify::stringify) } } + impl Stringify for Expr { fn try_into_lit(&self) -> Option { if let Expr::Lit(v) = self { @@ -107,7 +114,6 @@ impl Stringify for Expr { fn stringify(&self) -> TokenStream { self.try_into_lit() .as_ref() - .map(Stringify::stringify) - .unwrap_or_else(|| stringify_at_runtime(self)) + .map_or_else(|| stringify_at_runtime(self), Stringify::stringify) } } diff --git a/packages/yew-macro/tests/html_macro/node-fail.stderr b/packages/yew-macro/tests/html_macro/node-fail.stderr index fc94b419875..05676a5c9be 100644 --- a/packages/yew-macro/tests/html_macro/node-fail.stderr +++ b/packages/yew-macro/tests/html_macro/node-fail.stderr @@ -10,25 +10,15 @@ error: unexpected token, expected `}` 5 | html! { { "valid" "invalid" } }; | ^^^^^^^^^ -error: unsupported type - --> tests/html_macro/node-fail.rs:10:14 - | -10 | html! { b'a' }; - | ^^^^ - -error: unsupported type +error: byte-strings can't be converted to HTML text + note: remove the `b` prefix or convert this to a `String` --> tests/html_macro/node-fail.rs:11:14 | 11 | html! { b"str" }; | ^^^^^^ -error: unsupported type - --> tests/html_macro/node-fail.rs:12:22 - | -12 | html! { { b'a' } }; - | ^^^^ - -error: unsupported type +error: byte-strings can't be converted to HTML text + note: remove the `b` prefix or convert this to a `String` --> tests/html_macro/node-fail.rs:13:22 | 13 | html! { { b"str" } }; diff --git a/packages/yew-macro/tests/html_macro/node-pass.rs b/packages/yew-macro/tests/html_macro/node-pass.rs index ed38c3e77cf..38aad870ad3 100644 --- a/packages/yew-macro/tests/html_macro/node-pass.rs +++ b/packages/yew-macro/tests/html_macro/node-pass.rs @@ -37,12 +37,12 @@ pub struct u8; pub struct usize; fn main() { - _ = ::yew::html! { "" }; + _ = ::yew::html! { b'b' }; _ = ::yew::html! { 'a' }; _ = ::yew::html! { "hello" }; - _ = ::yew::html! { "42" }; - _ = ::yew::html! { "1.234" }; - _ = ::yew::html! { "true" }; + _ = ::yew::html! { 42 }; + _ = ::yew::html! { 1.234 }; + _ = ::yew::html! { true }; _ = ::yew::html! { { "" } }; _ = ::yew::html! { { 'a' } };