use super::funejson::Value; /// The samples with from <= at < to. Half-open, so consecutive windows /// (the last hour, the hour before) never count a sample twice. /// /// # Panics /// Panics when from is after to, or the samples are not strictly ascending. pub fn series_window(samples: &[MetricSample], from: i64, to: i64) -> Vec { if from > to { panic!("from must not be after to: {} > {}", from, to); } let mut out = Vec::new(); for (i, s) in samples.iter().enumerate() { // Checked over the whole series, not just the window: a misordered // store gives wrong answers everywhere, so it should fail everywhere. if i > 0 && s.at <= samples[i - 1].at { panic!("samples must be in strictly ascending time order: {} follows {}", s.at, samples[i - 1].at); } if s.at >= from && s.at < to { out.push(MetricSample { at: s.at, value: s.value }); } } out } /// A `MetricSample` from its JSON form, for adapters of capabilities built on this one. pub fn sample_from_value(v: &Value) -> MetricSample { MetricSample { at: v.get("at").as_i64(), value: v.get("value").as_i64() } } pub fn samples_from_value(v: &Value) -> Vec { v.as_arr().iter().map(sample_from_value).collect() } pub fn sample_to_value(s: &MetricSample) -> Value { Value::obj(vec![("at", Value::Int(s.at)), ("value", Value::Int(s.value))]) } fn whole(v: &Value) -> i64 { match v { Value::Int(i) => *i, _ => panic!("from and to must be whole seconds"), } } pub fn fune_vector(args: &[Value]) -> Value { let samples = samples_from_value(&args[0]); let out = series_window(&samples, whole(&args[1]), whole(&args[2])); Value::Arr(out.iter().map(sample_to_value).collect()) }