use std::fmt;
use std::io::Write;
use super::Filter;
use crate::error::{Result, ResultLiquidExt, ResultLiquidReplaceExt};
use crate::model::{ValueCow, ValueView};
use crate::runtime::Expression;
use crate::runtime::Renderable;
use crate::runtime::Runtime;
#[derive(Debug)]
pub struct FilterChain {
entry: Expression,
filters: Vec<Box<dyn Filter>>,
}
impl FilterChain {
pub fn new(entry: Expression, filters: Vec<Box<dyn Filter>>) -> Self {
Self { entry, filters }
}
pub fn evaluate<'s>(&'s self, runtime: &'s dyn Runtime) -> Result<ValueCow<'s>> {
let mut entry = self.entry.evaluate(runtime)?;
for filter in &self.filters {
entry = ValueCow::Owned(
filter
.evaluate(entry.as_view(), runtime)
.trace("Filter error")
.context_key("filter")
.value_with(|| format!("{}", filter).into())
.context_key("input")
.value_with(|| format!("{}", entry.source()).into())?,
);
}
Ok(entry)
}
}
impl fmt::Display for FilterChain {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{} | {}",
self.entry,
itertools::join(&self.filters, " | ")
)
}
}
impl Renderable for FilterChain {
fn render_to(&self, writer: &mut dyn Write, runtime: &dyn Runtime) -> Result<()> {
let entry = self.evaluate(runtime)?;
write!(writer, "{}", entry.render()).replace("Failed to render")?;
Ok(())
}
}