fhtml-macros 0.6.1

Macro implementations for `fhtml`
Documentation
use core::fmt;
use std::vec::IntoIter;

use syn::parse::Parse;

use crate::ast;

#[cfg_attr(test, derive(Debug, PartialEq))]
pub(crate) enum AstPart<Value: fmt::Display> {
    Doctype,
    OpeningTagStart,
    OpeningTagName(ast::DashIdent),
    OpeningTagEnd,
    ClosingTagStart,
    ClosingTagName(ast::DashIdent),
    ClosingTagEnd,
    AttrName(ast::DashIdent),
    AttrValueStart,
    AttrValue(Value),
    AttrValueEnd,
    Value(Value),
}

impl<Value: Parse + fmt::Display> IntoIterator for ast::Attr<Value> {
    type IntoIter = core::array::IntoIter<AstPart<Value>, 4>;
    type Item = AstPart<Value>;

    fn into_iter(self) -> Self::IntoIter {
        [
            AstPart::AttrName(self.name),
            AstPart::AttrValueStart,
            AstPart::AttrValue(self.value),
            AstPart::AttrValueEnd,
        ]
        .into_iter()
    }
}

impl<Value: Parse + fmt::Display> IntoIterator for ast::Tag<Value> {
    type IntoIter = IntoIter<AstPart<Value>>;
    type Item = AstPart<Value>;

    fn into_iter(self) -> Self::IntoIter {
        match self {
            Self::Opening { name, attrs, .. } => {
                let mut v = vec![
                    AstPart::OpeningTagStart,
                    AstPart::OpeningTagName(name),
                ];
                for attr in attrs {
                    v.extend(attr.into_iter())
                }
                v.push(AstPart::OpeningTagEnd);
                v
            }
            Self::Closing { name } => vec![
                AstPart::ClosingTagStart,
                AstPart::ClosingTagName(name),
                AstPart::ClosingTagEnd,
            ],
        }
        .into_iter()
    }
}

impl<Value: Parse + fmt::Display> IntoIterator for ast::Node<Value> {
    type IntoIter = IntoIter<AstPart<Value>>;
    type Item = AstPart<Value>;

    fn into_iter(self) -> Self::IntoIter {
        match self {
            ast::Node::Doctype(_) => vec![AstPart::Doctype].into_iter(),
            ast::Node::Tag(tag) => tag.into_iter(),
            ast::Node::Value(value) => vec![AstPart::Value(value)].into_iter(),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    macro_rules! dash_ident {
        ($($arg:tt)*) => {
            syn::parse2::<crate::ast::DashIdent>(
                quote::quote! { $($arg)* }
            ).unwrap()
        }
    }

    #[test]
    fn opening_tags() {
        assert_eq!(
            ast::Tag::<ast::LitValue>::Opening {
                name: dash_ident!(foo),
                attrs: vec![],
                self_closing: false
            }
            .into_iter()
            .collect::<Vec<_>>(),
            vec![
                AstPart::OpeningTagStart,
                AstPart::OpeningTagName(dash_ident!(foo)),
                AstPart::OpeningTagEnd,
            ]
        );
    }
}