premise 0.1.5

the core pattern library of Premise: sequences, tables, records, money, days and text, every function carrying the reason it exists
Documentation
use patterns_macros::because;

pub fn either<T>(when: bool, yes: T, no: T) -> T {
    if when {
        yes
    } else {
        no
    }
}

pub fn is_below<T: PartialOrd>(a: T, b: T) -> bool {
    a < b
}

pub fn is_above<T: PartialOrd>(a: T, b: T) -> bool {
    a > b
}

pub fn is_at_most<T: PartialOrd>(a: T, b: T) -> bool {
    a <= b
}

pub fn is_at_least<T: PartialOrd>(a: T, b: T) -> bool {
    a >= b
}

pub fn is_same<T: PartialEq>(a: T, b: T) -> bool {
    a == b
}
because!(either, "the replacement for an if expression in a binding, so a choice between two values is a call and the branch cannot grow a body");
because!(is_below, "a strict ordering test named so a comparison operator never appears in spec or app");
because!(is_above, "the mirror of is_below, named rather than derived because negating a strict comparison flips to a non-strict one and that is a common error");
because!(is_at_most, "the non-strict form of is_below, separate because the boundary case is exactly what a limit turns on");
because!(is_at_least, "the non-strict form of is_above, separate because the boundary case is exactly what a limit turns on");
because!(is_same, "equality as a call, so an equality operator never appears in spec or app");

pub fn either_lazily<T>(when: bool, yes: fn() -> T, no: fn() -> T) -> T {
    if when {
        yes()
    } else {
        no()
    }
}
because!(either_lazily, "the form that builds only the branch it returns, for a choice whose arms are expensive or whose unused arm would panic; either is eager and evaluates both arguments before the call");

pub fn refuse_when<E, F: Clone>(checks: &[(bool, F)], ok: E) -> Result<E, F> {
    for (refused, fault) in checks {
        if *refused {
            return Err(fault.clone());
        }
    }
    Ok(ok)
}
because!(refuse_when, "a table of guards read top to bottom, the first true one refusing with its fault, so a decide arm with several rules is a list in the order the rules apply rather than a nest of either calls that reads inside out; every guard is built before the call, and refuse_when_lazily is the form for a guard that must not run until an earlier one has passed");

pub type Guard<S, C, F> = (fn(&S, &C) -> bool, F);

pub fn refuse_when_lazily<S, C, E, F: Clone>(
    state: &S,
    command: &C,
    checks: &[Guard<S, C, F>],
    ok: E,
) -> Result<E, F> {
    for (refused, fault) in checks {
        if refused(state, command) {
            return Err(fault.clone());
        }
    }
    Ok(ok)
}
because!(refuse_when_lazily, "the guard table of refuse_when with each guard a function of the state and the command, run only until the first refusal, kept beside refuse_when because an eager table builds every guard before the call and a guard that is only safe to evaluate after an earlier one has refused cannot be written that way");

pub fn flipped(value: bool) -> bool {
    !value
}
because!(flipped, "a flag turned over, which a binding cannot write because the negation operator is control flow to the checker, and which the first setting that toggles needs before anything else in a project works");