use super::funejson::Value; const LIMIT: i64 = 1000; // 100.0 °C in tenths fn check_temperature(what: &str, value: i64) { if value < -LIMIT || value > LIMIT { panic!("{} must be whole tenths of a degree from -1000 to 1000, received {}", what, value); } } /// Heating and cooling degree days in tenths: each day adds how far its mean /// fell below (heating) or rose above (cooling) the base. /// /// # Panics /// Panics if a temperature is outside -100.0 to 100.0 °C. pub fn degree_days(daily_mean_temperatures: &[i64], base_temperature: i64) -> DegreeDays { check_temperature("base temperature", base_temperature); let mut heating = 0; let mut cooling = 0; for &mean in daily_mean_temperatures { check_temperature("daily mean temperature", mean); if mean < base_temperature { heating += base_temperature - mean; } else if mean > base_temperature { cooling += mean - base_temperature; } } DegreeDays { heating, cooling, days: daily_mean_temperatures.len() as i64, } } pub fn degree_days_to_value(d: &DegreeDays) -> Value { Value::obj(vec![ ("heating", Value::Int(d.heating)), ("cooling", Value::Int(d.cooling)), ("days", Value::Int(d.days)), ]) } fn whole_tenths(what: &str, v: &Value) -> i64 { if let Value::Float(f) = v { panic!("{} must be whole tenths of a degree from -1000 to 1000, received {}", what, f); } v.as_i64() } pub fn fune_vector(args: &[Value]) -> Value { let temps: Vec = args[0] .as_arr() .iter() .map(|v| whole_tenths("daily mean temperature", v)) .collect(); let base = whole_tenths("base temperature", &args[1]); degree_days_to_value(°ree_days(&temps, base)) }