yew-html-ext 0.3.2

Handy syntactic extensions for Yew's HTML macros
Documentation
use super::{AsVNode, HtmlTree};
use crate::{OptionExt, PeekValue};
use proc_macro2::TokenStream;
use quote::{quote, quote_spanned, ToTokens};
use syn::{
    braced,
    buffer::Cursor,
    parse::{Parse, ParseStream},
    spanned::Spanned,
    token::Brace,
    Expr, Pat, Token,
};

pub struct HtmlMatchArm {
    pat: Pat,
    guard: Option<(Token![if], Expr)>,
    fat_arrow_token: Token![=>],
    body: AsVNode<HtmlTree>,
}

impl Parse for HtmlMatchArm {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        let pat = Pat::parse_multi_with_leading_vert(input)?;
        let guard = match <Token![if]>::parse(input) {
            Ok(if_token) => Some((if_token, input.parse()?)),
            Err(_) => None,
        };
        let fat_arrow_token = input.parse()?;
        let body = input.parse()?;
        Ok(Self {
            pat,
            guard,
            fat_arrow_token,
            body,
        })
    }
}

impl ToTokens for HtmlMatchArm {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let Self {
            pat,
            guard,
            fat_arrow_token,
            body,
        } = self;
        let (if_token, guard) = guard.unzip_ref();
        tokens.extend(quote! { #pat #if_token #guard #fat_arrow_token #body })
    }
}

pub struct HtmlMatch {
    match_token: Token![match],
    expr: Expr,
    brace: Brace,
    arms: Vec<HtmlMatchArm>,
}

impl PeekValue<()> for HtmlMatch {
    fn peek(cursor: Cursor) -> Option<()> {
        cursor
            .ident()
            .filter(|(ident, _)| ident == "match")
            .map(drop)
    }
}

impl Parse for HtmlMatch {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        let match_token = input.parse()?;
        let expr = Expr::parse_without_eager_brace(input)?;
        let body;
        let brace = braced!(body in input);
        let arms = body
            .parse_terminated(HtmlMatchArm::parse, Token![,])?
            .into_iter()
            .collect();
        Ok(Self {
            match_token,
            expr,
            brace,
            arms,
        })
    }
}

impl ToTokens for HtmlMatch {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let Self {
            match_token,
            expr,
            brace,
            arms,
        } = self;
        tokens.extend(quote_spanned! {brace.span.span()=>
            #match_token #expr {
                #(#arms),*
            }
        })
    }
}