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::dates_days_between::days_between; ← from dates.days-between ^1.0.0 · built alongside by fune
use super::energy_meter_advance::meter_advance; ← from energy.meter-advance ^1.0.0 · built alongside by fune
use super::math_round_div::round_div; ← from math.round-div ^1.0.0 · built alongside by fune
const MAX_SAFE: i128 = 9_007_199_254_740_991;
/// Carry the latest read forward to `on_date` at the average daily
/// consumption between the two reads, rounding once, and wrap past all nines.
///
/// # Panics
/// Panics on reads that do not fit the register, reads in the wrong order, a
/// target date before the latest read, or an estimate too large to be exact.
pub fn estimate_read(
earlier_read: &MeterRead,
latest_read: &MeterRead,
on_date: &str,
digits: i64,
mode: &str,
) -> EstimatedRead {
let consumption = meter_advance(earlier_read.value, latest_read.value, digits);
let history = days_between(&earlier_read.date, &latest_read.date);
if history <= 0 {
panic!(
"the earlier read must be dated before the latest read, received {} and {}",
earlier_read.date, latest_read.date
);
}
let ahead = days_between(&latest_read.date, on_date);
if ahead < 0 {
panic!(
"onDate must not be before the latest read, received {} and {}",
on_date, latest_read.date
);
}
let product = consumption as i128 * ahead as i128;
if product > MAX_SAFE {
panic!("estimate too large to calculate exactly");
}
let units = round_div(product as i64, history, mode);
let span = 10_i64.pow(digits as u32);
let raw = latest_read.value + units;
EstimatedRead {
read: raw % span,
units,
rolled_over: raw >= span,
}
}
pub fn meter_read_from_value(v: &Value) -> MeterRead {
if let Value::Float(f) = v.get("value") {
panic!("reads must be whole numbers, received {}", f);
}
MeterRead {
date: v.get("date").as_str().to_string(),
value: v.get("value").as_i64(),
}
}
pub fn estimated_read_to_value(e: &EstimatedRead) -> Value {
Value::obj(vec![
("read", Value::Int(e.read)),
("units", Value::Int(e.units)),
("rolledOver", Value::Bool(e.rolled_over)),
])
}
pub fn fune_vector(args: &[Value]) -> Value {
estimated_read_to_value(&estimate_read(
&meter_read_from_value(&args[0]),
&meter_read_from_value(&args[1]),
args[2].as_str(),
args[3].as_i64(),
args[4].as_str(),
))
}