1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
//! Helpers for numerical comparisons.
//!
//! Arguments must be numerical values otherwise a type assertion
//! error is returned.
//!
//! Values are compared as `f64`.
use crate::{
    error::HelperError,
    helper::{Helper, HelperValue},
    parser::ast::Node,
    render::{Context, Render, Type},
};

use serde_json::Value;

fn cmp<'call, F>(ctx: &Context<'call>, cmp: F) -> HelperValue
where
    F: FnOnce(f64, f64) -> bool,
{
    ctx.arity(2..2)?;

    let lhs = ctx.try_get(0, &[Type::Number])?;
    let rhs = ctx.try_get(1, &[Type::Number])?;

    match (lhs, rhs) {
        (Value::Number(lhs), Value::Number(rhs)) => {
            if let (Some(lhs), Some(rhs)) = (lhs.as_f64(), rhs.as_f64()) {
                Ok(Some(Value::Bool(cmp(lhs, rhs))))
            } else {
                Err(HelperError::InvalidNumericalOperand(
                    ctx.name().to_string(),
                ))
            }
        }
        _ => Err(HelperError::InvalidNumericalOperand(ctx.name().to_string())),
    }
}

/// Perform an equality comparison.
pub struct Equal;

impl Helper for Equal {
    fn call<'render, 'call>(
        &self,
        _rc: &mut Render<'render>,
        ctx: &Context<'call>,
        _template: Option<&'render Node<'render>>,
    ) -> HelperValue {
        cmp(ctx, |lhs: f64, rhs: f64| lhs == rhs)
    }
}

/// Perform a negated equality comparison.
pub struct NotEqual;

impl Helper for NotEqual {
    fn call<'render, 'call>(
        &self,
        _rc: &mut Render<'render>,
        ctx: &Context<'call>,
        _template: Option<&'render Node<'render>>,
    ) -> HelperValue {
        cmp(ctx, |lhs: f64, rhs: f64| lhs != rhs)
    }
}

/// Perform a numerical greater than comparison.
pub struct GreaterThan;

impl Helper for GreaterThan {
    fn call<'render, 'call>(
        &self,
        _rc: &mut Render<'render>,
        ctx: &Context<'call>,
        _template: Option<&'render Node<'render>>,
    ) -> HelperValue {
        cmp(ctx, |lhs: f64, rhs: f64| lhs > rhs)
    }
}

/// Perform a numerical greater than or equal comparison.
pub struct GreaterThanEqual;

impl Helper for GreaterThanEqual {
    fn call<'render, 'call>(
        &self,
        _rc: &mut Render<'render>,
        ctx: &Context<'call>,
        _template: Option<&'render Node<'render>>,
    ) -> HelperValue {
        cmp(ctx, |lhs: f64, rhs: f64| lhs >= rhs)
    }
}

/// Perform a numerical less than comparison.
pub struct LessThan;

impl Helper for LessThan {
    fn call<'render, 'call>(
        &self,
        _rc: &mut Render<'render>,
        ctx: &Context<'call>,
        _template: Option<&'render Node<'render>>,
    ) -> HelperValue {
        cmp(ctx, |lhs: f64, rhs: f64| lhs < rhs)
    }
}

/// Perform a numerical less than comparison.
pub struct LessThanEqual;

impl Helper for LessThanEqual {
    fn call<'render, 'call>(
        &self,
        _rc: &mut Render<'render>,
        ctx: &Context<'call>,
        _template: Option<&'render Node<'render>>,
    ) -> HelperValue {
        cmp(ctx, |lhs: f64, rhs: f64| lhs <= rhs)
    }
}