Functional Weave
Code in TypeScript

energy.solar-generation@1.0.0

impl/rust.rs

1,997 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
use super::math_round_div::round_div;  ← from math.round-div ^1.0.0 · built alongside by fune

// watts x Kk x SF (hundredths) / (1000 W/kW x 100) is kWh.
const DIVISOR: i64 = 100_000;

fn check(what: &str, value: i64, max: i64) {
    if value < 0 || value > max {
        panic!("{} must be a whole number from 0 to {}, received {}", what, max, value);
    }
}

/// Annual AC generation by the MCS method, kWp x Kk x SF, rounded half-up to
/// a whole kWh for each array; the total is the sum of the arrays.
///
/// # Panics
/// Panics on no arrays, or a rating, Kk or shade factor out of range.
pub fn solar_generation(arrays: &[PvArray]) -> SolarEstimate {
    if arrays.is_empty() {
        panic!("a solar estimate needs at least one array");
    }
    let kwh: Vec<i64> = arrays
        .iter()
        .map(|a| {
            check("wattsPeak", a.watts_peak, 100_000_000);
            check("kk", a.kk, 5000);
            check("shadeFactor", a.shade_factor, 100);
            round_div(a.watts_peak * a.kk * a.shade_factor, DIVISOR, "half-up")
        })
        .collect();
    let total = kwh.iter().sum();
    SolarEstimate { arrays: kwh, total }
}

fn whole(what: &str, max: i64, v: &Value) -> i64 {
    if let Value::Float(f) = v {
        panic!("{} must be a whole number from 0 to {}, received {}", what, max, f);
    }
    v.as_i64()
}

pub fn pv_array_from_value(v: &Value) -> PvArray {
    PvArray {
        watts_peak: whole("wattsPeak", 100_000_000, v.get("wattsPeak")),
        kk: whole("kk", 5000, v.get("kk")),
        shade_factor: whole("shadeFactor", 100, v.get("shadeFactor")),
    }
}

pub fn solar_estimate_to_value(e: &SolarEstimate) -> Value {
    Value::obj(vec![
        ("arrays", Value::Arr(e.arrays.iter().map(|k| Value::Int(*k)).collect())),
        ("total", Value::Int(e.total)),
    ])
}

pub fn fune_vector(args: &[Value]) -> Value {
    let arrays: Vec<PvArray> = args[0].as_arr().iter().map(pv_array_from_value).collect();
    solar_estimate_to_value(&solar_generation(&arrays))
}