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::math_round_float::round_float; ← from math.round-float ^1.0.0 · built alongside by fune
/// Seed rate (kg/ha) = target plants/m² x TGW (g) / expected establishment (%).
///
/// The TGW is taken to the centigram and the establishment is in basis points,
/// so kg/ha is exactly plants x centigrams / basis points and is rounded once.
/// Doing it in floats gets 100 x 1.15 / 100 = 1.1499999999999999, which rounds
/// to 1.1 kg/ha instead of 1.2.
///
/// # Panics
/// Panics when an argument is out of range.
pub fn seed_rate(target_plants_per_square_metre: i64, thousand_grain_weight_grams: f64, establishment_basis_points: i64) -> SeedRate {
let plants = target_plants_per_square_metre;
if !(1..=100000).contains(&plants) {
panic!("targetPlantsPerSquareMetre must be a whole number from 1 to 100000, received {}", plants);
}
let tgw = thousand_grain_weight_grams;
if !tgw.is_finite() || tgw <= 0.0 || tgw > 1000.0 {
panic!("thousandGrainWeightGrams must be a finite number greater than 0 and at most 1000, received {}", tgw);
}
let centigrams = (round_float(tgw, 2) * 100.0).round() as i64;
if centigrams < 1 {
panic!("thousandGrainWeightGrams must be at least 0.01 grams, received {}", tgw);
}
let bp = establishment_basis_points;
if !(1..=10000).contains(&bp) {
panic!("establishmentBasisPoints must be a whole number from 1 to 10000, received {}", bp);
}
SeedRate {
kg_per_hectare: round_div(plants * centigrams * 10, bp, "half-up") as f64 / 10.0,
seeds_per_square_metre: round_div(plants * 100000, bp, "half-up") as f64 / 10.0,
}
}
pub fn seed_rate_to_value(s: &SeedRate) -> Value {
Value::obj(vec![
("kgPerHectare", Value::Float(s.kg_per_hectare)),
("seedsPerSquareMetre", Value::Float(s.seeds_per_square_metre)),
])
}
fn whole(v: &Value, message: &str) -> i64 {
match v {
Value::Int(i) => *i,
_ => panic!("{}, received {:?}", message, v),
}
}
pub fn fune_vector(args: &[Value]) -> Value {
let plants = whole(&args[0], "targetPlantsPerSquareMetre must be a whole number from 1 to 100000");
let bp = whole(&args[2], "establishmentBasisPoints must be a whole number from 1 to 10000");
seed_rate_to_value(&seed_rate(plants, args[1].as_f64(), bp))
}