atom-engine 5.0.2

A component-oriented template engine built on Tera with props, slots, and provide/inject context
Documentation
use crate::types::value::Value;

pub fn num_round(n: f64, decimals: Option<i32>) -> Value {
    let d = decimals.unwrap_or(0);
    let multiplier = 10_f64.powi(d);
    Value::Num((n * multiplier).round() / multiplier)
}

pub fn num_floor(n: f64) -> Value {
    Value::Num(n.floor())
}

pub fn num_ceil(n: f64) -> Value {
    Value::Num(n.ceil())
}

pub fn num_abs(n: f64) -> Value {
    Value::Num(n.abs())
}

pub fn num_clamp(n: f64, min: f64, max: f64) -> Value {
    Value::Num(n.max(min).min(max))
}

pub fn num_to_fixed(n: f64, decimals: i32) -> Value {
    Value::Str(format!("{:.width$}", n, width = decimals as usize))
}

pub fn num_format(n: f64) -> Value {
    Value::Str(
        format!("{:.0}", n)
            .chars()
            .rev()
            .collect::<Vec<_>>()
            .chunks(3)
            .map(|c| c.iter().collect::<String>())
            .collect::<Vec<_>>()
            .join(",")
            .chars()
            .rev()
            .collect(),
    )
}

pub fn num_currency(n: f64, symbol: Option<&str>) -> Value {
    let sym = symbol.unwrap_or("$");
    Value::Str(format!("{}{:.2}", sym, n))
}

pub fn num_percent(n: f64, decimals: Option<i32>) -> Value {
    let d = decimals.unwrap_or(0);
    Value::Str(format!("{:.width$}%", n * 100.0, width = d as usize))
}

pub fn num_is_even(n: f64) -> Value {
    Value::Bool(n as i64 % 2 == 0)
}

pub fn num_is_odd(n: f64) -> Value {
    Value::Bool(n as i64 % 2 != 0)
}

pub fn num_pad(n: f64, width: usize, ch: Option<char>) -> Value {
    let pad_char = ch.unwrap_or('0');
    Value::Str(
        format!("{:<width$}", n.to_string(), width = width).replace(' ', &pad_char.to_string()),
    )
}

pub fn num_min(a: f64, b: f64) -> Value {
    Value::Num(a.min(b))
}

pub fn num_max(a: f64, b: f64) -> Value {
    Value::Num(a.max(b))
}

pub fn num_random(min: i64, max: i64) -> Value {
    use std::time::{SystemTime, UNIX_EPOCH};
    let seed = SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .unwrap()
        .as_nanos() as u64;
    let range = (max - min + 1) as u64;
    let result = (seed % range) as i64 + min;
    Value::Num(result as f64)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_round() {
        assert_eq!(num_round(3.14159, Some(2)), Value::Num(3.14));
    }

    #[test]
    fn test_floor() {
        assert_eq!(num_floor(3.9), Value::Num(3.0));
    }

    #[test]
    fn test_ceil() {
        assert_eq!(num_ceil(3.1), Value::Num(4.0));
    }

    #[test]
    fn test_abs() {
        assert_eq!(num_abs(-5.0), Value::Num(5.0));
    }

    #[test]
    fn test_clamp() {
        assert_eq!(num_clamp(5.0, 0.0, 10.0), Value::Num(5.0));
        assert_eq!(num_clamp(-1.0, 0.0, 10.0), Value::Num(0.0));
        assert_eq!(num_clamp(15.0, 0.0, 10.0), Value::Num(10.0));
    }

    #[test]
    fn test_is_even() {
        assert!(num_is_even(4.0).is_truthy());
        assert!(!num_is_even(3.0).is_truthy());
    }

    #[test]
    fn test_is_odd() {
        assert!(num_is_odd(3.0).is_truthy());
        assert!(!num_is_odd(4.0).is_truthy());
    }

    #[test]
    fn test_min() {
        assert_eq!(num_min(3.0, 5.0), Value::Num(3.0));
    }

    #[test]
    fn test_max() {
        assert_eq!(num_max(3.0, 5.0), Value::Num(5.0));
    }
}