Functional Weave
Code in Rust

charts.scale@1.1.0

impl/rust/log_scale.rs

1,331 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::charts_scale_linear_scale::{floats, interpolate, pair};  ← linearScale, another function of this group · built into the same file, even by a slim install
use super::math_ln::ln;  ← from math.ln ^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

/// Where `value` lands on a logarithmic axis: equal ratios take equal lengths.
/// The base cancels out, so there is none to pass. `ln` is math.ln, not
/// `f64::ln`, so every language lands on the same double.
///
/// # Panics
/// Panics if the domain or range does not have two values, either domain end
/// is not positive, the ends are equal, or `value` is not positive.
pub fn log_scale(domain: &[f64], range: &[f64], value: f64, clamp: bool) -> f64 {
    let (d0, d1) = pair(domain, "domain");
    let (r0, r1) = pair(range, "range");
    if !(d0 > 0.0) || !(d1 > 0.0) {
        panic!("log scale domain must be positive; got [{}, {}]", d0, d1);
    }
    if d0 == d1 {
        panic!("domain has no width: both ends are {}", d0);
    }
    if !(value > 0.0) {
        panic!("value must be positive for a log scale; got {}", value);
    }
    let l0 = ln(d0);
    let mut t = (ln(value) - l0) / (ln(d1) - l0);
    if clamp {
        t = t.max(0.0).min(1.0);
    }
    round_float(interpolate(r0, r1, t), 6)
}

pub fn fune_vector(args: &[Value]) -> Value {
    Value::Float(log_scale(&floats(&args[0]), &floats(&args[1]), args[2].as_f64(), args[3].as_bool()))
}