CorrosionMark 0.1.1

This is a markdown parser libary
Documentation
use crate::{
    error::CorrError, ASTElement, FormattedTextBlock, ListItem, ListItemType, TextFormat, AST,
};
use std::fmt::Write;

pub trait RenderHTML {
    fn render(input: &Self) -> Result<String, CorrError>;
}

impl RenderHTML for TextFormat {
    fn render(input: &Self) -> Result<String, CorrError> {
        let mut return_value = String::new();
        match input {
            Self::Bold(bold_input) => {
                write! {return_value, "<b>{}</b>", bold_input
                .iter()
                .map(Self::render)
                .collect::<Result<String, CorrError>>()?}?;
            }
            Self::StrikeThrough(striketrough_input) => {
                write! {return_value, "<s>{}</s>", striketrough_input
                .iter()
                .map(Self::render)
                .collect::<Result<String, CorrError>>()?}?;
            }
            Self::Italic(italic_input) => {
                write! {return_value, "<i>{}</i>", italic_input.iter()
                .map(Self::render)
                .collect::<Result<String, CorrError>>()?}?;
            }
            Self::Link { name, href } => {
                write! {return_value, "<a href=\" {} \">{}</a>", href, name.iter()
                .map(Self::render)
                .collect::<Result<String, CorrError>>()?}?;
            }
            Self::Text(text_input) => {
                return_value = text_input.clone();
            }
        };
        Ok(return_value)
    }
}

impl RenderHTML for FormattedTextBlock {
    fn render(input: &Self) -> Result<String, CorrError> {
        input
            .inhalt
            .iter()
            .map(TextFormat::render)
            .collect::<Result<String, CorrError>>()
    }
}

impl RenderHTML for ASTElement {
    fn render(input: &Self) -> Result<String, CorrError> {
        let mut output = String::new();
        match input {
            Self::Heading { text, tier } => {
                write! {output, "<h{}>{}</h{}>", tier, FormattedTextBlock::render(text)?, tier}?;
            }
            Self::TextBlock { text } => {
                write! {output, "<p>{}</p>", FormattedTextBlock::render(text)?}?;
            }
            Self::Image {
                link_text,
                link_url,
                image_alt,
                image_url,
            } => {
                write! {output,
                    "<a href=\"{}\"><img src=\"{}\" alt=\"{}\">{}</a>",
                    match link_url {
                        Some(inhalt) => inhalt,
                        None => "",
                    },
                    image_url ,
                    match image_alt {
                        Some(inhalt) => inhalt,
                        None => "",
                    },
                    match link_text {
                        Some(inhalt) => inhalt,
                        None => "",
                    },
                }?;
            }
            Self::Liste { elements } => {
                output += "<ul>";
                let mut lvl: usize = 0;

                for current_element in elements {
                    while current_element.level != lvl {
                        if current_element.level > lvl {
                            output += "<ul>";
                            lvl = lvl.saturating_add(1);
                        } else {
                            output += "</ul>";
                            lvl = lvl.saturating_sub(1);
                        }
                    }

                    write! {output, "{}", ListItem::render(current_element)?}?
                }
                while 0 != lvl {
                    output += "</ul>";
                    lvl = lvl.saturating_sub(1);
                }
                output += "</ul>";
            }
            Self::Table { headers, inhalt } => {
                write! {output,
                    "<table><tr>{}</tr>{}<table>",
                    headers.iter()
                        .map(|one_header_element| -> Result<String, CorrError> {Ok(String::from("</th>") + &FormattedTextBlock::render(one_header_element)? + "</th>")})
                        .collect::<Result<String, CorrError>>()?, Self::render_inhalt_table(inhalt)?
                }?;
            }
        };

        Ok(output)
    }
}

impl ASTElement {
    fn render_inhalt_table(input: &Vec<Vec<FormattedTextBlock>>) -> Result<String, CorrError> {
        let mut output = String::new();

        for single_row in input {
            write! {output,
            "<tr>{}<tr>",
            single_row.iter()
                .map(|parsed| -> Result<String, CorrError> {
                    let mut one_cell = String::new();
                    write! {one_cell, "<td>{}</td>", FormattedTextBlock::render(parsed)?}?;
                    Ok(one_cell)})
                .collect::<Result<String, CorrError>>()?}?
        }

        Ok(output)
    }
}

impl RenderHTML for ListItem {
    fn render(input: &Self) -> Result<String, CorrError> {
        let mut output = String::new();
        match input.item_type {
            ListItemType::Unordered => {
                write! {output, "<li>- {}<li>", FormattedTextBlock::render(&input.content)?}?
            }
            ListItemType::Ordered(inhalt) => {
                write! {output, "<li>{}. {}<li>", inhalt ,FormattedTextBlock::render(&input.content)?}?
            }
        };
        Ok(output)
    }
}

impl RenderHTML for AST {
    fn render(input: &Self) -> Result<String, CorrError> {
        input
            .root
            .iter()
            .map(ASTElement::render)
            .collect::<Result<String, CorrError>>()
    }
}