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_gcd_lcm::gcd_wide; ← from math.gcd-lcm ^1.0.0 · built alongside by fune
const MAX_SAFE: i128 = 9_007_199_254_740_991;
/// Reduce a wide fraction and bring it back into the exact number range. The
/// arithmetic works on i128 products, which may be past 2^53, and only the
/// reduced result has to fit.
///
/// # Panics
/// Panics if the denominator is zero or the reduced result is outside ±(2^53 - 1).
pub fn rational_from_wide(numerator: i128, denominator: i128) -> Rational {
if denominator == 0 {
panic!("denominator must not be zero");
}
let g = gcd_wide(numerator, denominator);
let mut n = numerator / g;
let mut d = denominator / g;
if d < 0 {
n = -n;
d = -d;
}
// i64 could hold more, but TypeScript numbers stop being exact here, and
// the three languages must agree.
if n > MAX_SAFE || n < -MAX_SAFE || d > MAX_SAFE {
panic!("rational overflow: the reduced result exceeds 2^53 - 1");
}
Rational {
numerator: n as i64,
denominator: d as i64,
}
}
/// Build a reduced fraction with a positive denominator.
///
/// # Panics
/// Panics if the denominator is zero or either part is outside ±(2^53 - 1).
pub fn rational(numerator: i64, denominator: i64) -> Rational {
let (n, d) = (numerator as i128, denominator as i128);
if n > MAX_SAFE || n < -MAX_SAFE || d > MAX_SAFE || d < -MAX_SAFE {
panic!("rational overflow: numerator and denominator must be within 2^53 - 1");
}
rational_from_wide(n, d)
}
/// A checked, reduced operand as i128s, ready to multiply without overflow.
pub fn rational_parts(r: &Rational) -> (i128, i128) {
let n = rational(r.numerator, r.denominator);
(n.numerator as i128, n.denominator as i128)
}
pub fn rational_to_value(r: &Rational) -> Value {
Value::obj(vec![
("numerator", Value::Int(r.numerator)),
("denominator", Value::Int(r.denominator)),
])
}
/// Read an integer from JSON, refusing a fraction with the wording TypeScript
/// and Python use rather than let `as_i64` quietly truncate it.
pub fn rational_int_from_value(v: &Value) -> i64 {
if let Value::Float(f) = v {
if f.fract() != 0.0 {
panic!("numerator and denominator must be integers");
}
}
v.as_i64()
}
pub fn rational_from_value(v: &Value) -> Rational {
Rational {
numerator: rational_int_from_value(v.get("numerator")),
denominator: rational_int_from_value(v.get("denominator")),
}
}
pub fn fune_vector(args: &[Value]) -> Value {
rational_to_value(&rational(
rational_int_from_value(&args[0]),
rational_int_from_value(&args[1]),
))
}