diff --git a/src/interpreter/filter.rs b/src/interpreter/filter.rs index ed57f32..7618a69 100644 --- a/src/interpreter/filter.rs +++ b/src/interpreter/filter.rs @@ -3,7 +3,9 @@ use std::{ sync::{Arc, LazyLock}, }; -use super::{ElementContext, TryFromValue, Value}; +use anyhow::Context as _; + +use super::{value::Or, ElementContext, TryFromValue, Value}; pub use filter_proc_macro::{filter_fn, Args}; @@ -99,6 +101,32 @@ fn take<'doc>( Ok(value.remove(&key).unwrap_or(Value::Null)) } +#[filter_fn] +fn int<'doc>(value: Or>>) -> anyhow::Result> { + let n = match value { + Or::A(n) => n, + Or::B(Or::A(x)) => x as i64, + Or::B(Or::B(s)) => s + .parse() + .with_context(|| format!("`{s}` is not an integer."))?, + }; + + Ok(Value::Int(n)) +} + +#[filter_fn] +fn float<'doc>(value: Or>>) -> anyhow::Result> { + let x = match value { + Or::A(x) => x, + Or::B(Or::A(n)) => n as f64, + Or::B(Or::B(s)) => s + .parse() + .with_context(|| format!("`{s}` is not a float."))?, + }; + + Ok(Value::Float(x)) +} + macro_rules! build_map { ($( $id: ident, @@ -118,6 +146,8 @@ static BUILTIN_FILTERS: LazyLock From> for Value<'a> { Self::Element(value) } } + +#[derive(Debug, Clone)] +pub enum Or { + A(A), + B(B), +} + +impl<'a, A: TryFromValue<'a>, B: TryFromValue<'a>> TryFromValue<'a> for Or { + fn try_from_value(value: Value<'a>) -> anyhow::Result { + match value.clone().try_into() { + Ok(a) => Ok(Self::A(a)), + Err(a) => match value.try_into() { + Ok(b) => Ok(Self::B(b)), + Err(b) => anyhow::bail!("Error: {a} or {b}"), + }, + } + } +}