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
// 1.02264 / 3.6 in lowest terms, with the scales of the arguments folded in:
// watt-hours = hundredths of m³ x 4261 x CV (thousandths of MJ/m³) / 1,500,000.
const FACTOR: i64 = 4261;
const DIVISOR: i64 = 1_500_000;
const MAX_VOLUME: i64 = 1_000_000_000_000;
const MAX_SAFE: i128 = 9_007_199_254_740_991;
/// Gas meter units to kWh, the way a GB bill does it: volume (x 2.83 for an
/// imperial meter) x 1.02264 x calorific value / 3.6, rounded once, half-up,
/// to the watt-hour.
///
/// # Panics
/// Panics on a volume or calorific value out of range, an unknown unit, or a
/// result too large to be exact in every language.
pub fn gas_kwh(volume: i64, volume_unit: &str, calorific_value: i64) -> GasEnergy {
if volume < 0 || volume > MAX_VOLUME {
panic!("volume must be a whole number of units from 0 to {}, received {}", MAX_VOLUME, volume);
}
if !(1..=100000).contains(&calorific_value) {
panic!(
"calorific value must be a whole number of thousandths of a MJ/m³ from 1 to 100000, received {}",
calorific_value
);
}
let hundredths = match volume_unit {
"cubic-metres" => volume * 100,
"hundreds-cubic-feet" => volume * 283,
other => panic!("unknown volume unit \"{}\": expected cubic-metres or hundreds-cubic-feet", other),
};
let scaled = FACTOR * calorific_value;
let whole = hundredths / DIVISOR;
let rest = hundredths % DIVISOR;
let watt_hours = whole as i128 * scaled as i128 + round_div(rest * scaled, DIVISOR, "half-up") as i128;
if watt_hours > MAX_SAFE {
panic!("gas energy too large to calculate exactly");
}
GasEnergy {
cubic_metres_hundredths: hundredths,
watt_hours: watt_hours as i64,
}
}
pub fn gas_energy_to_value(e: &GasEnergy) -> Value {
Value::obj(vec![
("cubicMetresHundredths", Value::Int(e.cubic_metres_hundredths)),
("wattHours", Value::Int(e.watt_hours)),
])
}
pub fn fune_vector(args: &[Value]) -> Value {
if let Value::Float(f) = &args[0] {
panic!("volume must be a whole number of units, received {}", f);
}
if let Value::Float(f) = &args[2] {
panic!("calorific value must be a whole number of thousandths of a MJ/m³, received {}", f);
}
gas_energy_to_value(&gas_kwh(args[0].as_i64(), args[1].as_str(), args[2].as_i64()))
}