lunar-lib 0.8.0

Common utilities for lunar applications
Documentation
use std::{collections::HashMap, convert::Infallible};

use crate::formatter::{Render, Taggable, Template, TemplateError};

/// The format table for `key=value` pairs used when rendering `Arguments`, like in `format()`
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct FormatTable {
    table: HashMap<String, String>,
}

impl FormatTable {
    /// Creates a new, empty format table
    pub fn new() -> Self {
        Self {
            table: HashMap::new(),
        }
    }

    /// Renders a template to a string, replacing tags with values from the table
    pub fn render(&self, template: &Template) -> String {
        template.render(self)
    }

    pub fn render_string(&self, str: impl AsRef<str>) -> Result<String, TemplateError> {
        let args = Template::try_from(str.as_ref())?;
        Ok(self.render(&args))
    }

    /// Adds a single `key=value` pair to the table
    pub fn add_entry(&mut self, key: impl Into<String>, value: impl Into<String>) {
        self.table
            .insert(key.into().to_ascii_lowercase(), value.into());
    }

    /// Extends the table with an iterator of `key=value` pairs
    pub fn add_table<I, K, V>(&mut self, table: I)
    where
        I: IntoIterator<Item = (K, V)>,
        K: Into<String>,
        V: Into<String>,
    {
        self.table
            .extend(table.into_iter().map(|(k, v)| (k.into(), v.into())));
    }

    /// Extends the table with any [`Taggable`]
    pub fn extend_from_taggable<T: Taggable>(&mut self, from: &T) -> Result<(), T::Err> {
        from.fill_table(self)
    }

    /// Gets the the held table of `self`
    pub fn table(&self) -> &HashMap<String, String> {
        &self.table
    }
}

impl Taggable for FormatTable {
    type Err = Infallible;

    fn fill_table(&self, table: &mut FormatTable) -> Result<(), Infallible> {
        table.table.extend(self.table.clone());
        Ok(())
    }
}

impl<I, K, V> From<I> for FormatTable
where
    I: IntoIterator<Item = (K, V)>,
    K: Into<String>,
    V: Into<String>,
{
    fn from(value: I) -> Self {
        FormatTable::from_iter(value)
    }
}

impl<K, V> FromIterator<(K, V)> for FormatTable
where
    K: Into<String>,
    V: Into<String>,
{
    fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
        FormatTable {
            table: iter
                .into_iter()
                .map(|(k, v)| (k.into(), v.into()))
                .collect(),
        }
    }
}