use crate::{
ast::{Argument, FormatString, Segment, Span},
error::Error,
parser,
renderer::Renderer,
};
use std::{fmt, str::FromStr};
pub struct Template {
source: String,
parsed: FormatString,
}
impl Template {
pub fn new<S: Into<String>>(source: S) -> Result<Self, Error> {
let source = source.into();
let parsed = parser::parse(&source)?;
Ok(Self { source, parsed })
}
pub fn render(&self) -> Renderer<'_> {
Renderer::new(self)
}
pub fn contains(&self, name: &str) -> bool {
self.parsed.segments.iter().any(|seg| {
if let Segment::Placeholder(p) = seg
&& let Argument::Named(span) = &p.argument
{
return self.resolve(*span) == name;
}
false
})
}
pub fn placeholders(&self) -> Vec<&str> {
self.parsed
.segments
.iter()
.filter_map(|seg| {
if let Segment::Placeholder(p) = seg
&& let Argument::Named(span) = &p.argument
{
return Some(self.resolve(*span));
}
None
})
.collect::<Vec<_>>()
}
pub fn source(&self) -> &str {
&self.source
}
pub(crate) fn parsed(&self) -> &FormatString {
&self.parsed
}
pub(crate) fn resolve(&self, span: Span) -> &str {
&self.source[span.start..span.end]
}
}
impl fmt::Display for Template {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.source)
}
}
impl fmt::Debug for Template {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Template")
.field("source", &self.source)
.finish()
}
}
impl FromStr for Template {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::new(s)
}
}