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
use super::money_amount::{assert_same_currency, money, money_from_value, money_to_value, Money}; ← from money.amount ^1.0.0 · built alongside by fune
/// Usage against a bundle: remaining allowance, overage in whole blocks priced
/// and limited to an optional cap, and the share used, rounded down so a
/// bundle with anything left never reads 100%.
///
/// # Panics
/// Panics on negative quantities or prices, a block below 1, or a cap in
/// another currency.
pub fn data_allowance(allowance: i64, used: i64, overage_block: i64, price_per_block: &Money, overage_cap: Option<&Money>) -> DataAllowance {
if allowance < 0 || used < 0 {
panic!(
"allowance and usage must be whole numbers of 0 or more, received {} and {}",
allowance, used
);
}
if overage_block < 1 {
panic!("overage block must be 1 or more, received {}", overage_block);
}
if price_per_block.minor < 0 {
panic!("price per block must not be negative, received {}", price_per_block.minor);
}
if let Some(cap) = overage_cap {
assert_same_currency(price_per_block, cap);
if cap.minor < 0 {
panic!("overage cap must not be negative, received {}", cap.minor);
}
}
let overage = (used - allowance).max(0);
let overage_blocks = round_div(overage, overage_block, "up");
let uncapped = overage_blocks * price_per_block.minor;
let cap_minor = overage_cap.map(|c| c.minor);
let capped = matches!(cap_minor, Some(c) if uncapped > c);
DataAllowance {
used,
remaining: (allowance - used).max(0),
overage,
overage_blocks,
overage_charge: money(
if capped { cap_minor.unwrap() } else { uncapped },
&price_per_block.currency,
),
capped,
percent_used_basis_points: if allowance == 0 {
None
} else {
Some(round_div(used * 10000, allowance, "down"))
},
}
}
pub fn data_allowance_to_value(d: &DataAllowance) -> Value {
Value::obj(vec![
("used", Value::Int(d.used)),
("remaining", Value::Int(d.remaining)),
("overage", Value::Int(d.overage)),
("overageBlocks", Value::Int(d.overage_blocks)),
("overageCharge", money_to_value(&d.overage_charge)),
("capped", Value::Bool(d.capped)),
(
"percentUsedBasisPoints",
match d.percent_used_basis_points {
Some(n) => Value::Int(n),
None => Value::Null,
},
),
])
}
pub fn fune_vector(args: &[Value]) -> Value {
let cap = if args[4].is_null() { None } else { Some(money_from_value(&args[4])) };
data_allowance_to_value(&data_allowance(
args[0].as_i64(),
args[1].as_i64(),
args[2].as_i64(),
&money_from_value(&args[3]),
cap.as_ref(),
))
}