flowstdlib 1.0.0

The standard library of functions and flows for 'flow' programs
Documentation
use serde_json::{json, Value};

use flowcore::errors::Result;
use flowcore::flow_output;
use flowcore::RunAgain;
use flowmacro::flow_function;

#[flow_function]
fn inner_divide(dividend: &Value, divisor: &Value) -> Result<(Option<Value>, RunAgain)> {
    if dividend.is_null() || divisor.is_null() {
        return flow_output!("result" => Value::Null, "remainder" => Value::Null);
    }

    let dividend = dividend
        .as_f64()
        .ok_or("Could not get dividend as number")?;
    let divisor = divisor.as_f64().ok_or("Could not get divisor as number")?;

    flow_output!(
        "result" => json!(dividend / divisor),
        "remainder" => json!(dividend % divisor)
    )
}

#[cfg(test)]
#[allow(clippy::unwrap_used, clippy::expect_used)]
mod test {
    use serde_json::{json, Value};

    use super::inner_divide;

    #[test]
    fn divide_exact() {
        let (output, again) = inner_divide(&json!(99), &json!(3)).expect("divide failed");
        assert!(again);
        let out = output.expect("no output");
        assert_eq!(*out.pointer("/result").expect("no result"), json!(33.0));
        assert_eq!(
            *out.pointer("/remainder").expect("no remainder"),
            json!(0.0)
        );
    }

    #[test]
    fn divide_with_remainder() {
        let (output, _) = inner_divide(&json!(100), &json!(3)).expect("divide failed");
        let out = output.expect("no output");
        let result = out
            .pointer("/result")
            .expect("no result")
            .as_f64()
            .expect("not f64");
        assert!((result - 33.333_333_333_333_336).abs() < 1e-10);
    }

    #[test]
    fn divide_floats() {
        let (output, _) = inner_divide(&json!(10.5), &json!(2.5)).expect("divide failed");
        let out = output.expect("no output");
        assert_eq!(*out.pointer("/result").expect("no result"), json!(4.2));
    }

    #[test]
    fn divide_mixed_int_and_float() {
        let (output, _) = inner_divide(&json!(10), &json!(2.5)).expect("divide failed");
        let out = output.expect("no output");
        assert_eq!(*out.pointer("/result").expect("no result"), json!(4.0));
    }

    #[test]
    fn divide_null_propagation() {
        let (output, _) = inner_divide(&json!(null), &json!(5)).expect("divide failed");
        let out = output.expect("no output");
        assert_eq!(*out.pointer("/result").expect("no result"), Value::Null);
        assert_eq!(
            *out.pointer("/remainder").expect("no remainder"),
            Value::Null
        );
    }
}