Functional Weave
Code in Python

energy.price-cap@1.0.2

impl/rust.rs

3,311 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::energy_price_cap_data::{PRICE_CAP, PRICE_CAP_HISTORY};  ← this capability’s own data, compiled from data/price-cap.json into the same file by fune build

fn is_iso_date(value: &str) -> bool {
    let bytes = value.as_bytes();
    bytes.len() == 10
        && bytes[4] == b'-'
        && bytes[7] == b'-'
        && bytes.iter().enumerate().all(|(i, b)| i == 4 || i == 7 || b.is_ascii_digit())
}

/// The Ofgem price cap unit rate and standing charge in force on `on_date`.
///
/// # Panics
/// Panics on a malformed date, an unknown fuel or payment method, a payment
/// method with no figures, or a date outside every period carried.
pub fn price_cap(fuel: &str, payment_method: &str, on_date: &str) -> PriceCap {
    if !is_iso_date(on_date) {
        panic!("onDate must be an ISO date (YYYY-MM-DD), received \"{}\"", on_date);
    }
    if fuel != "electricity" && fuel != "gas" {
        panic!("unknown fuel \"{}\": expected electricity or gas", fuel);
    }
    if !["direct-debit", "standard-credit", "prepayment"].contains(&payment_method) {
        panic!(
            "unknown payment method \"{}\": expected direct-debit, standard-credit or prepayment",
            payment_method
        );
    }
    let rows: Vec<_> = PRICE_CAP
        .iter()
        .filter(|r| r.fuel == fuel && r.payment_method == payment_method)
        .collect();
    if rows.is_empty() {
        panic!(
            "no price cap figures for {} paid by {}: this version carries GB-average Direct Debit figures only",
            fuel, payment_method
        );
    }
    let row = match rows.iter().find(|r| r.valid_from <= on_date && on_date <= r.valid_to) {
        Some(row) => row,
        None => {
            // A pruned build must not answer an old date with a newer cap.
            if PRICE_CAP_HISTORY != "full" {
                let earliest = rows.iter().map(|r| r.valid_from).min().unwrap();
                if on_date < earliest {
                    panic!(
                        "no price cap for {}/{} on {}: this build was installed with history={}, so it only carries periods from {}. Reinstall with history=full for older dates.",
                        fuel, payment_method, on_date, PRICE_CAP_HISTORY, earliest
                    );
                }
            }
            panic!("no price cap for {}/{} on {}", fuel, payment_method, on_date)
        }
    };
    PriceCap {
        fuel: fuel.to_string(),
        payment_method: payment_method.to_string(),
        region: row.region.to_string(),
        unit_rate: row.unit_rate,
        standing_charge: row.standing_charge,
        vat_basis_points: row.vat_basis_points,
        valid_from: row.valid_from.to_string(),
        valid_to: row.valid_to.to_string(),
    }
}

pub fn price_cap_to_value(p: &PriceCap) -> Value {
    Value::obj(vec![
        ("fuel", Value::str(&p.fuel)),
        ("paymentMethod", Value::str(&p.payment_method)),
        ("region", Value::str(&p.region)),
        ("unitRate", Value::Int(p.unit_rate)),
        ("standingCharge", Value::Int(p.standing_charge)),
        ("vatBasisPoints", Value::Int(p.vat_basis_points)),
        ("validFrom", Value::str(&p.valid_from)),
        ("validTo", Value::str(&p.valid_to)),
    ])
}

pub fn fune_vector(args: &[Value]) -> Value {
    price_cap_to_value(&price_cap(args[0].as_str(), args[1].as_str(), args[2].as_str()))
}