simple-rsx 0.1.1

A simple JSX-like syntax implementation for Rust
Documentation
pub use simple_rsx_macros::rsx;
use std::fmt::Display;

pub enum NodeList {
    Fragment(Vec<Node>),
    Single(Node),
}

impl Display for NodeList {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            NodeList::Fragment(nodes) => {
                for node in nodes {
                    write!(f, "{}", node)?;
                }
                Ok(())
            }
            NodeList::Single(node) => {
                write!(f, "{}", node)?;
                Ok(())
            }
        }
    }
}

pub enum Node {
    Element(Element),
    Text(String),
}

impl Display for Node {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Node::Element(el) => {
                write!(f, "<{}", el.tag)?;
                for (key, value) in &el.attributes {
                    write!(f, " {}=\"{}\"", key, value)?;
                }
                write!(f, ">")?;
                for child in &el.children {
                    write!(f, "{}", child)?;
                }
                write!(f, "</{}>", el.tag)?;
                Ok(())
            }
            Node::Text(text) => {
                write!(f, "{}", text)?;
                Ok(())
            }
        }
    }
}

pub trait AttributeValue {
    fn value(&self) -> String;
}

impl<T: ToString> AttributeValue for T {
    fn value(&self) -> String {
        self.to_string()
    }
}

pub struct Element {
    tag: String,
    attributes: std::collections::HashMap<String, String>,
    children: Vec<Node>,
}

impl Element {
    pub fn new(tag: &str) -> Node {
        Node::Element(Element {
            tag: tag.to_string(),
            attributes: std::collections::HashMap::new(),
            children: Vec::new(),
        })
    }

    pub fn set_attribute(&mut self, name: &str, value: impl AttributeValue) {
        self.attributes.insert(name.to_string(), value.value());
    }

    pub fn append_child(&mut self, node: Node) {
        self.children.push(node);
    }
}

impl Node {
    pub fn as_element_mut(&mut self) -> Option<&mut Element> {
        match self {
            Node::Element(el) => Some(el),
            _ => None,
        }
    }

    pub fn append_child(&mut self, node: Node) {
        if let Node::Element(el) = self {
            el.children.push(node);
        }
    }
}

pub struct TextNode;

impl TextNode {
    pub fn new(text: &str) -> Node {
        Node::Text(text.to_string())
    }
}