pub mod component;
use std::fmt::{
Error,
Write,
};
use thiserror::Error;
use crate::{
template::component::Component,
value::Values,
};
trait Expand {
fn expand(&self, values: &Values, write: &mut impl Write) -> Result<(), ExpandError>;
}
trait Parse<'t>
where
Self: Sized,
{
fn parse(raw: &'t str, global: usize) -> (usize, Self);
}
trait TryParse<'t>
where
Self: Sized,
{
fn try_parse(raw: &'t str, base: usize) -> Result<(usize, Self), ParseError>;
}
#[derive(Debug, Error)]
pub enum ExpandError {
#[error("formatting failed")]
Format(#[from] Error),
}
#[derive(Debug, Error)]
pub enum ParseError {
#[error("{message} at position: {position}. expected: {expected}.")]
UnexpectedInput {
position: usize,
message: String,
expected: String,
},
}
#[derive(Debug, Eq, PartialEq)]
pub struct Template<'t> {
components: Vec<Component<'t>>,
}
impl<'t> Template<'t> {
pub fn expand(&self, values: &Values) -> Result<String, ExpandError> {
let mut expanded = String::default();
Expand::expand(self, values, &mut expanded)?;
Ok(expanded)
}
pub fn parse(raw: &'t str) -> Result<Self, ParseError> {
Self::try_parse(raw, 0).map(|(_, template)| template)
}
const fn new(components: Vec<Component<'t>>) -> Self {
Self { components }
}
}
impl<'t> TryParse<'t> for Template<'t> {
fn try_parse(raw: &'t str, global: usize) -> Result<(usize, Self), ParseError> {
Vec::<Component<'t>>::try_parse(raw, global)
.map(|(position, components)| (position, Self::new(components)))
}
}
impl<'t> Expand for Template<'t> {
fn expand(&self, values: &Values, write: &mut impl Write) -> Result<(), ExpandError> {
self.components
.iter()
.try_for_each(|component| component.expand(values, write))
}
}