Functional Weave
Code in Rust

charts.scale@1.1.0

impl/rust/time_scale.rs

1,285 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::dates_days_between::days_between;  ← from dates.days-between ^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 an ISO date lands on the range, linearly by calendar days, counted
/// with dates.days-between so no time zone can move a point by a day.
///
/// # Panics
/// Panics if the domain or range does not have two values, a date is not a
/// real ISO date, or the domain's ends are the same day.
pub fn time_scale(domain: &[String], range: &[f64], value: &str, clamp: bool) -> f64 {
    if domain.len() != 2 {
        panic!("domain must have exactly 2 values, [from, to]; got {}", domain.len());
    }
    let (r0, r1) = pair(range, "range");
    let span = days_between(&domain[0], &domain[1]);
    if span == 0 {
        panic!("domain has no width: both ends are {}", domain[0]);
    }
    let mut t = days_between(&domain[0], value) as f64 / span as f64;
    if clamp {
        t = t.max(0.0).min(1.0);
    }
    round_float(interpolate(r0, r1, t), 6)
}

pub fn fune_vector(args: &[Value]) -> Value {
    let domain: Vec<String> = args[0].as_arr().iter().map(|v| v.as_str().to_string()).collect();
    Value::Float(time_scale(&domain, &floats(&args[1]), args[2].as_str(), args[3].as_bool()))
}