Functional Weave
Code in Python

monitor.format-duration@1.0.0

impl/rust.rs

1,855 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

const UNITS: [(&str, i64); 4] = [("d", 86400), ("h", 3600), ("m", 60), ("s", 1)];

/// Seconds as "3h 12m". Starts at the largest non-zero unit and looks at
/// `max_units` consecutive units from there, leaving out the zero ones, so
/// 3605 s with two units is "1h", not "1h 0m" and not "1h 5s": the seconds
/// are beyond the precision asked for. Truncates, never rounds up, so a
/// duration is never shown longer than it was (86399 s is "23h", not "1d").
///
/// # Panics
/// Panics on negative seconds or max_units outside 1..=4.
pub fn format_duration(seconds: i64, max_units: i64) -> String {
    if seconds < 0 {
        panic!("seconds must not be negative, received {}", seconds);
    }
    if !(1..=4).contains(&max_units) {
        panic!("maxUnits must be 1 to 4, received {}", max_units);
    }
    if seconds == 0 {
        return "0s".to_string();
    }
    let mut first = 0usize;
    while seconds / UNITS[first].1 == 0 {
        first += 1;
    }
    let mut parts: Vec<String> = Vec::new();
    let mut rest = seconds;
    for (i, (label, size)) in UNITS.iter().enumerate() {
        let n = rest / size;
        rest -= n * size;
        if i >= first && (i as i64) < first as i64 + max_units && n > 0 {
            parts.push(format!("{}{}", n, label));
        }
    }
    parts.join(" ")
}

pub fn fune_vector(args: &[Value]) -> Value {
    let seconds = match &args[0] {
        Value::Int(i) => *i,
        Value::Float(f) => panic!("seconds must be a whole number, received {}", f),
        _ => panic!("seconds must be a whole number"),
    };
    let max_units = match &args[1] {
        Value::Int(i) => *i,
        Value::Float(f) => panic!("maxUnits must be 1 to 4, received {}", f),
        _ => panic!("maxUnits must be 1 to 4"),
    };
    Value::str(&format_duration(seconds, max_units))
}