yew_macro/html_tree/
html_node.rs1use proc_macro2::{Span, TokenStream};
2use quote::{quote, quote_spanned, ToTokens};
3use syn::buffer::Cursor;
4use syn::parse::{Parse, ParseStream, Result};
5use syn::spanned::Spanned;
6use syn::{Expr, Lit};
7
8use super::ToNodeIterator;
9use crate::stringify::Stringify;
10use crate::PeekValue;
11
12pub enum HtmlNode {
13 Literal(Box<Lit>),
14 Expression(Box<Expr>),
15}
16
17impl Parse for HtmlNode {
18 fn parse(input: ParseStream) -> Result<Self> {
19 let node = if HtmlNode::peek(input.cursor()).is_some() {
20 let lit = input.parse()?;
21 match lit {
22 Lit::ByteStr(lit) => {
23 return Err(syn::Error::new(
24 lit.span(),
25 "byte-strings can't be converted to HTML text
26 note: remove the `b` prefix or convert this to a `String`",
27 ))
28 }
29 Lit::Verbatim(lit) => {
30 return Err(syn::Error::new(lit.span(), "unsupported literal"))
31 }
32 _ => (),
33 }
34 HtmlNode::Literal(Box::new(lit))
35 } else {
36 HtmlNode::Expression(Box::new(input.parse()?))
37 };
38
39 Ok(node)
40 }
41}
42
43impl PeekValue<()> for HtmlNode {
44 fn peek(cursor: Cursor) -> Option<()> {
45 cursor.literal().map(|_| ()).or_else(|| {
46 let (ident, _) = cursor.ident()?;
47 match ident.to_string().as_str() {
48 "true" | "false" => Some(()),
49 _ => None,
50 }
51 })
52 }
53}
54
55impl ToTokens for HtmlNode {
56 fn to_tokens(&self, tokens: &mut TokenStream) {
57 tokens.extend(match &self {
58 HtmlNode::Literal(lit) => {
59 let sr = lit.stringify();
60 quote_spanned! {lit.span()=> ::yew::virtual_dom::VText::new(#sr) }
61 }
62 HtmlNode::Expression(expr) => quote! {#expr},
63 });
64 }
65}
66
67impl ToNodeIterator for HtmlNode {
68 fn to_node_iterator_stream(&self) -> Option<TokenStream> {
69 match self {
70 HtmlNode::Literal(_) => None,
71 HtmlNode::Expression(expr) => {
72 Some(quote_spanned! {expr.span().resolved_at(Span::call_site())=>
74 ::std::convert::Into::<::yew::utils::NodeSeq<_, _>>::into(#expr)
75 })
76 }
77 }
78 }
79}