Functional Weave
Code in Python

manufacturing.tolerance-check@1.0.0

impl/rust.rs

2,815 bytes · the Rust implementation · view raw

Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.

use super::funejson::Value;  ← the fune runtime: the JSON value the test vectors use; fune build keeps it only where a signature takes one

const LIMIT: i64 = 1_000_000_000_000;

fn micrometres(name: &str, value: i64) {
    if !(-LIMIT..=LIMIT).contains(&value) {
        panic!("{} must be a whole number of micrometres within ±10^12, received {}", name, value);
    }
}

/// Check a measurement against nominal plus its upper and lower deviations.
///
/// The deviations are signed and independent, so a tolerance band that lies
/// wholly above or below nominal (an H7 hole, a g6 shaft) is checked
/// correctly; a symmetric band is just `+t, -t`.
///
/// # Panics
/// Panics on a value beyond ±10^12 µm, or a lower deviation above the upper.
pub fn check_tolerance(measured: i64, nominal: i64, upper_deviation: i64, lower_deviation: i64) -> ToleranceCheck {
    micrometres("measured", measured);
    micrometres("nominal", nominal);
    micrometres("upperDeviation", upper_deviation);
    micrometres("lowerDeviation", lower_deviation);
    if lower_deviation > upper_deviation {
        panic!(
            "lowerDeviation must not be greater than upperDeviation, received {} and {}",
            lower_deviation, upper_deviation
        );
    }
    let lower_limit = nominal + lower_deviation;
    let upper_limit = nominal + upper_deviation;
    let deviation = measured - nominal;
    let (passed, status, out_by) = if measured > upper_limit {
        (false, "above", measured - upper_limit)
    } else if measured < lower_limit {
        (false, "below", lower_limit - measured)
    } else {
        (true, "within", 0)
    };
    ToleranceCheck {
        passed,
        status: status.to_string(),
        deviation,
        lower_limit,
        upper_limit,
        out_by,
    }
}

pub fn tolerance_check_to_value(result: &ToleranceCheck) -> Value {
    Value::obj(vec![
        ("passed", Value::Bool(result.passed)),
        ("status", Value::str(&result.status)),
        ("deviation", Value::Int(result.deviation)),
        ("lowerLimit", Value::Int(result.lower_limit)),
        ("upperLimit", Value::Int(result.upper_limit)),
        ("outBy", Value::Int(result.out_by)),
    ])
}

pub fn fune_vector(args: &[Value]) -> Value {
    // Refuse what an i64 cannot hold, with the wording the other languages use.
    let names = ["measured", "nominal", "upperDeviation", "lowerDeviation"];
    for (i, name) in names.iter().enumerate() {
        match &args[i] {
            Value::Int(_) => {}
            Value::Float(f) => panic!("{} must be a whole number of micrometres within ±10^12, received {}", name, f),
            other => panic!("{} must be a whole number of micrometres within ±10^12, received {}", name, other),
        }
    }
    tolerance_check_to_value(&check_tolerance(
        args[0].as_i64(),
        args[1].as_i64(),
        args[2].as_i64(),
        args[3].as_i64(),
    ))
}