use crate::binsdim0::BinsDim0; use crate::eventsxbindim0::EventsXbinDim0; use crate::framable::FrameType; use crate::ts_offs_from_abs_with_anchor; use crate::IsoDateTime; use crate::RangeOverlapInfo; use crate::TimeBinnableType; use crate::TimeBinnableTypeAggregator; use err::Error; use items_0::collect_s::Collectable; use items_0::collect_s::CollectableType; use items_0::collect_s::Collected; use items_0::collect_s::CollectorType; use items_0::collect_s::ToJsonBytes; use items_0::collect_s::ToJsonResult; use items_0::container::ByteEstimate; use items_0::overlap::HasTimestampDeque; use items_0::scalar_ops::ScalarOps; use items_0::timebin::TimeBinnable; use items_0::timebin::TimeBinned; use items_0::timebin::TimeBinner; use items_0::Appendable; use items_0::AsAnyMut; use items_0::AsAnyRef; use items_0::Empty; use items_0::Events; use items_0::EventsNonObj; use items_0::MergeError; use items_0::WithLen; use netpod::is_false; use netpod::log::*; use netpod::range::evrange::SeriesRange; use netpod::timeunits::MS; use netpod::timeunits::SEC; use netpod::BinnedRangeEnum; use serde::Deserialize; use serde::Serialize; use std::any; use std::any::Any; use std::collections::VecDeque; use std::fmt; use std::mem; #[allow(unused)] macro_rules! trace2 { (EN$($arg:tt)*) => (); ($($arg:tt)*) => (trace!($($arg)*)); } #[derive(Clone, PartialEq, Serialize, Deserialize)] pub struct EventsDim1NoPulse { pub tss: VecDeque, pub values: VecDeque>, } impl From> for EventsDim1 { fn from(value: EventsDim1NoPulse) -> Self { let pulses = vec![0; value.tss.len()].into(); Self { tss: value.tss, pulses, values: value.values, } } } #[derive(Clone, PartialEq, Serialize, Deserialize)] pub struct EventsDim1 { pub tss: VecDeque, pub pulses: VecDeque, pub values: VecDeque>, } impl EventsDim1 { #[inline(always)] pub fn push(&mut self, ts: u64, pulse: u64, value: Vec) { self.tss.push_back(ts); self.pulses.push_back(pulse); self.values.push_back(value); } #[inline(always)] pub fn push_front(&mut self, ts: u64, pulse: u64, value: Vec) { self.tss.push_front(ts); self.pulses.push_front(pulse); self.values.push_front(value); } pub fn serde_id() -> &'static str { "EventsDim1" } pub fn tss(&self) -> &VecDeque { &self.tss } } impl AsAnyRef for EventsDim1 where STY: ScalarOps, { fn as_any_ref(&self) -> &dyn Any { self } } impl AsAnyMut for EventsDim1 where STY: ScalarOps, { fn as_any_mut(&mut self) -> &mut dyn Any { self } } impl Empty for EventsDim1 { fn empty() -> Self { Self { tss: VecDeque::new(), pulses: VecDeque::new(), values: VecDeque::new(), } } } impl fmt::Debug for EventsDim1 where STY: fmt::Debug, { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { if false { write!( fmt, "EventsDim1 {{ count {} ts {:?} vals {:?} }}", self.tss.len(), self.tss.iter().map(|x| x / SEC).collect::>(), self.values, ) } else { write!( fmt, "EventsDim1 {{ count {} ts {:?} .. {:?} vals {:?} .. {:?} }}", self.tss.len(), self.tss.front().map(|x| x / SEC), self.tss.back().map(|x| x / SEC), self.values.front(), self.values.back(), ) } } } impl WithLen for EventsDim1 { fn len(&self) -> usize { self.tss.len() } } impl ByteEstimate for EventsDim1 { fn byte_estimate(&self) -> u64 { let stylen = mem::size_of::(); let n = self.values.front().map_or(0, Vec::len); (self.len() * (8 + 8 + n * stylen)) as u64 } } impl HasTimestampDeque for EventsDim1 { fn timestamp_min(&self) -> Option { self.tss.front().map(|x| *x) } fn timestamp_max(&self) -> Option { self.tss.back().map(|x| *x) } fn pulse_min(&self) -> Option { self.pulses.front().map(|x| *x) } fn pulse_max(&self) -> Option { self.pulses.back().map(|x| *x) } } items_0::impl_range_overlap_info_events!(EventsDim1); impl TimeBinnableType for EventsDim1 where STY: ScalarOps, { // TODO type Output = BinsDim0; type Aggregator = EventsDim1Aggregator; fn aggregator(range: SeriesRange, x_bin_count: usize, do_time_weight: bool) -> Self::Aggregator { let self_name = std::any::type_name::(); debug!( "TimeBinnableType for {self_name} aggregator() range {:?} x_bin_count {} do_time_weight {}", range, x_bin_count, do_time_weight ); Self::Aggregator::new(range, do_time_weight) } } #[derive(Debug, Serialize, Deserialize)] pub struct EventsDim1ChunkOutput { tss: VecDeque, pulses: VecDeque, values: VecDeque>, scalar_type: String, } impl EventsDim1ChunkOutput {} #[derive(Debug)] pub struct EventsDim1Collector { vals: EventsDim1, range_final: bool, timed_out: bool, needs_continue_at: bool, } impl EventsDim1Collector { pub fn self_name() -> &'static str { any::type_name::() } pub fn new() -> Self { Self { vals: EventsDim1::empty(), range_final: false, timed_out: false, needs_continue_at: false, } } } impl WithLen for EventsDim1Collector { fn len(&self) -> usize { WithLen::len(&self.vals) } } impl ByteEstimate for EventsDim1Collector { fn byte_estimate(&self) -> u64 { ByteEstimate::byte_estimate(&self.vals) } } #[derive(Debug, Serialize, Deserialize)] pub struct EventsDim1CollectorOutput { #[serde(rename = "tsAnchor")] ts_anchor_sec: u64, #[serde(rename = "tsMs")] ts_off_ms: VecDeque, #[serde(rename = "tsNs")] ts_off_ns: VecDeque, #[serde(rename = "pulseAnchor")] pulse_anchor: u64, #[serde(rename = "pulseOff")] pulse_off: VecDeque, #[serde(rename = "values")] values: VecDeque>, #[serde(rename = "rangeFinal", default, skip_serializing_if = "is_false")] range_final: bool, #[serde(rename = "timedOut", default, skip_serializing_if = "is_false")] timed_out: bool, #[serde(rename = "continueAt", default, skip_serializing_if = "Option::is_none")] continue_at: Option, } impl EventsDim1CollectorOutput { pub fn ts_anchor_sec(&self) -> u64 { self.ts_anchor_sec } pub fn ts_off_ms(&self) -> &VecDeque { &self.ts_off_ms } pub fn pulse_anchor(&self) -> u64 { self.pulse_anchor } pub fn pulse_off(&self) -> &VecDeque { &self.pulse_off } /// Note: only used for unit tests. pub fn values_to_f32(&self) -> VecDeque> { self.values .iter() .map(|x| x.iter().map(|x| x.as_prim_f32_b()).collect()) .collect() } pub fn range_final(&self) -> bool { self.range_final } pub fn timed_out(&self) -> bool { self.timed_out } pub fn is_valid(&self) -> bool { if self.ts_off_ms.len() != self.ts_off_ns.len() { false } else if self.ts_off_ms.len() != self.pulse_off.len() { false } else if self.ts_off_ms.len() != self.values.len() { false } else { true } } pub fn info_str(&self) -> String { use fmt::Write; let mut out = String::new(); write!( out, "ts_off_ms {} ts_off_ns {} pulse_off {} values {}", self.ts_off_ms.len(), self.ts_off_ns.len(), self.pulse_off.len(), self.values.len(), ) .unwrap(); out } } impl AsAnyRef for EventsDim1CollectorOutput where STY: ScalarOps, { fn as_any_ref(&self) -> &dyn Any { self } } impl AsAnyMut for EventsDim1CollectorOutput where STY: ScalarOps, { fn as_any_mut(&mut self) -> &mut dyn Any { self } } impl WithLen for EventsDim1CollectorOutput { fn len(&self) -> usize { self.values.len() } } impl ToJsonResult for EventsDim1CollectorOutput { fn to_json_result(&self) -> Result, Error> { let k = serde_json::to_value(self)?; Ok(Box::new(k)) } } impl Collected for EventsDim1CollectorOutput {} impl CollectorType for EventsDim1Collector { type Input = EventsDim1; type Output = EventsDim1CollectorOutput; fn ingest(&mut self, src: &mut Self::Input) { self.vals.tss.append(&mut src.tss); self.vals.pulses.append(&mut src.pulses); self.vals.values.append(&mut src.values); } fn set_range_complete(&mut self) { self.range_final = true; } fn set_timed_out(&mut self) { self.timed_out = true; } fn set_continue_at_here(&mut self) { debug!("{}::set_continue_at_here", Self::self_name()); self.needs_continue_at = true; } // TODO unify with dim0 case fn result( &mut self, range: Option, _binrange: Option, ) -> Result { // If we timed out, we want to hint the client from where to continue. // This is tricky: currently, client can not request a left-exclusive range. // We currently give the timestamp of the last event plus a small delta. // The amount of the delta must take into account what kind of timestamp precision the client // can parse and handle. let vals = &mut self.vals; let continue_at = if self.timed_out { if let Some(ts) = vals.tss.back() { Some(IsoDateTime::from_u64(*ts + MS)) } else { if let Some(range) = &range { match range { SeriesRange::TimeRange(x) => Some(IsoDateTime::from_u64(x.beg + SEC)), SeriesRange::PulseRange(x) => { error!("TODO emit create continueAt for pulse range"); Some(IsoDateTime::from_u64(0)) } } } else { warn!("can not determine continue-at parameters"); Some(IsoDateTime::from_u64(0)) } } } else { None }; let tss_sl = vals.tss.make_contiguous(); let pulses_sl = vals.pulses.make_contiguous(); let (ts_anchor_sec, ts_off_ms, ts_off_ns) = crate::ts_offs_from_abs(tss_sl); let (pulse_anchor, pulse_off) = crate::pulse_offs_from_abs(pulses_sl); let values = mem::replace(&mut vals.values, VecDeque::new()); if ts_off_ms.len() != ts_off_ns.len() { return Err(Error::with_msg_no_trace("collected len mismatch")); } if ts_off_ms.len() != pulse_off.len() { return Err(Error::with_msg_no_trace("collected len mismatch")); } if ts_off_ms.len() != values.len() { return Err(Error::with_msg_no_trace("collected len mismatch")); } let ret = Self::Output { ts_anchor_sec, ts_off_ms, ts_off_ns, pulse_anchor, pulse_off, values, range_final: self.range_final, timed_out: self.timed_out, continue_at, }; if !ret.is_valid() { error!("invalid:\n{}", ret.info_str()); } Ok(ret) } } impl CollectableType for EventsDim1 { type Collector = EventsDim1Collector; fn new_collector() -> Self::Collector { Self::Collector::new() } } #[derive(Debug)] pub struct EventsDim1Aggregator { range: SeriesRange, count: u64, min: STY, max: STY, sumc: u64, sum: f32, int_ts: u64, last_seen_ts: u64, last_seen_val: Option, did_min_max: bool, do_time_weight: bool, events_taken_count: u64, events_ignored_count: u64, } impl Drop for EventsDim1Aggregator { fn drop(&mut self) { // TODO collect as stats for the request context: trace!( "taken {} ignored {}", self.events_taken_count, self.events_ignored_count ); } } impl EventsDim1Aggregator { pub fn new(range: SeriesRange, do_time_weight: bool) -> Self { /*let int_ts = range.beg; Self { range, count: 0, min: NTY::zero_b(), max: NTY::zero_b(), sum: 0., sumc: 0, int_ts, last_seen_ts: 0, last_seen_val: None, did_min_max: false, do_time_weight, events_taken_count: 0, events_ignored_count: 0, }*/ todo!() } // TODO reduce clone.. optimize via more traits to factor the trade-offs? fn apply_min_max(&mut self, val: STY) { trace!( "apply_min_max val {:?} last_val {:?} count {} sumc {:?} min {:?} max {:?}", val, self.last_seen_val, self.count, self.sumc, self.min, self.max ); if self.did_min_max == false { self.did_min_max = true; self.min = val.clone(); self.max = val.clone(); } else { if self.min > val { self.min = val.clone(); } if self.max < val { self.max = val.clone(); } } } fn apply_event_unweight(&mut self, val: STY) { trace!("TODO check again result_reset_unweight"); err::todo(); let vf = val.as_prim_f32_b(); self.apply_min_max(val); if vf.is_nan() { } else { self.sum += vf; self.sumc += 1; } } fn apply_event_time_weight(&mut self, ts: u64) { /*if let Some(v) = &self.last_seen_val { let vf = v.as_prim_f32_b(); let v2 = v.clone(); if ts > self.range.beg { self.apply_min_max(v2); } let w = if self.do_time_weight { (ts - self.int_ts) as f32 * 1e-9 } else { 1. }; if vf.is_nan() { } else { self.sum += vf * w; self.sumc += 1; } self.int_ts = ts; } else { debug!( "apply_event_time_weight NO VALUE {}", ts as i64 - self.range.beg as i64 ); }*/ todo!() } fn ingest_unweight(&mut self, item: &::Input) { /*trace!("TODO check again result_reset_unweight"); err::todo(); for i1 in 0..item.tss.len() { let ts = item.tss[i1]; let val = item.values[i1].clone(); if ts < self.range.beg { self.events_ignored_count += 1; } else if ts >= self.range.end { self.events_ignored_count += 1; return; } else { error!("TODO ingest_unweight"); err::todo(); //self.apply_event_unweight(val); self.count += 1; self.events_taken_count += 1; } }*/ todo!() } fn ingest_time_weight(&mut self, item: &::Input) { /*let self_name = std::any::type_name::(); trace!("{self_name}::ingest_time_weight item len {}", item.len()); for i1 in 0..item.tss.len() { let ts = item.tss[i1]; let val = item.values[i1].clone(); trace!("{self_name} ingest {:6} {:20} {:10?}", i1, ts, val); if ts < self.int_ts { if self.last_seen_val.is_none() { info!( "ingest_time_weight event before range, only set last ts {} val {:?}", ts, val ); } self.events_ignored_count += 1; self.last_seen_ts = ts; error!("TODO ingest_time_weight"); err::todo(); //self.last_seen_val = Some(val); } else if ts >= self.range.end { self.events_ignored_count += 1; return; } else { if false && self.last_seen_val.is_none() { // TODO no longer needed or? info!( "call apply_min_max without last val, use current instead {} {:?}", ts, val ); // TODO: self.apply_min_max(val.clone()); } self.apply_event_time_weight(ts); self.count += 1; self.last_seen_ts = ts; error!("TODO ingest_time_weight"); err::todo(); //self.last_seen_val = Some(val); self.events_taken_count += 1; } }*/ todo!() } fn result_reset_unweight(&mut self, range: SeriesRange, _expand: bool) -> BinsDim0 { /*trace!("TODO check again result_reset_unweight"); err::todo(); let (min, max, avg) = if self.sumc > 0 { let avg = self.sum / self.sumc as f32; (self.min.clone(), self.max.clone(), avg) } else { let g = match &self.last_seen_val { Some(x) => x.clone(), None => NTY::zero_b(), }; (g.clone(), g.clone(), g.as_prim_f32_b()) }; let ret = BinsDim0 { ts1s: [self.range.beg].into(), ts2s: [self.range.end].into(), counts: [self.count].into(), mins: [min].into(), maxs: [max].into(), avgs: [avg].into(), }; self.int_ts = range.beg; self.range = range; self.count = 0; self.sum = 0f32; self.sumc = 0; self.did_min_max = false; ret*/ todo!() } fn result_reset_time_weight(&mut self, range: SeriesRange, expand: bool) -> BinsDim0 { // TODO check callsite for correct expand status. /*if expand { debug!("result_reset_time_weight calls apply_event_time_weight"); self.apply_event_time_weight(self.range.end); } else { debug!("result_reset_time_weight NO EXPAND"); } let (min, max, avg) = if self.sumc > 0 { let avg = self.sum / (self.range.delta() as f32 * 1e-9); (self.min.clone(), self.max.clone(), avg) } else { let g = match &self.last_seen_val { Some(x) => x.clone(), None => NTY::zero_b(), }; (g.clone(), g.clone(), g.as_prim_f32_b()) }; let ret = BinsDim0 { ts1s: [self.range.beg].into(), ts2s: [self.range.end].into(), counts: [self.count].into(), mins: [min].into(), maxs: [max].into(), avgs: [avg].into(), }; self.int_ts = range.beg; self.range = range; self.count = 0; self.sum = 0.; self.sumc = 0; self.did_min_max = false; self.min = NTY::zero_b(); self.max = NTY::zero_b(); ret*/ todo!() } } impl TimeBinnableTypeAggregator for EventsDim1Aggregator { type Input = EventsDim1; type Output = BinsDim0; fn range(&self) -> &SeriesRange { &self.range } fn ingest(&mut self, item: &Self::Input) { if true { trace!("{} ingest {} events", any::type_name::(), item.len()); } if false { for (i, &ts) in item.tss.iter().enumerate() { trace!("{} ingest {:6} {:20}", any::type_name::(), i, ts); } } if self.do_time_weight { self.ingest_time_weight(item) } else { self.ingest_unweight(item) } } fn result_reset(&mut self, range: SeriesRange) -> Self::Output { /*trace!("result_reset {} {}", range.beg, range.end); if self.do_time_weight { self.result_reset_time_weight(range, expand) } else { self.result_reset_unweight(range, expand) }*/ todo!() } } impl TimeBinnable for EventsDim1 { fn time_binner_new( &self, binrange: BinnedRangeEnum, do_time_weight: bool, emit_empty_bins: bool, ) -> Box { // TODO respect emit_empty_bins let ret = EventsDim1TimeBinner::::new(binrange, do_time_weight).unwrap(); Box::new(ret) } fn to_box_to_json_result(&self) -> Box { let k = serde_json::to_value(self).unwrap(); Box::new(k) as _ } } impl items_0::TypeName for EventsDim1 { fn type_name(&self) -> String { let sty = std::any::type_name::(); format!("EventsDim1<{sty}>") } } impl EventsNonObj for EventsDim1 { fn into_tss_pulses(self: Box) -> (VecDeque, VecDeque) { info!( "EventsDim1::into_tss_pulses len {} len {}", self.tss.len(), self.pulses.len() ); (self.tss, self.pulses) } } impl Events for EventsDim1 { fn as_time_binnable_ref(&self) -> &dyn TimeBinnable { self } fn as_time_binnable_mut(&mut self) -> &mut dyn TimeBinnable { self } fn verify(&self) -> bool { let mut good = true; let mut ts_max = 0; for ts in &self.tss { let ts = *ts; if ts < ts_max { good = false; error!("unordered event data ts {} ts_max {}", ts, ts_max); } ts_max = ts_max.max(ts); } good } fn output_info(&self) -> String { let n2 = self.tss.len().max(1) - 1; format!( "EventsDim1OutputInfo {{ len {}, ts_min {}, ts_max {} }}", self.tss.len(), self.tss.get(0).map_or(-1i64, |&x| x as i64), self.tss.get(n2).map_or(-1i64, |&x| x as i64), ) } fn as_collectable_mut(&mut self) -> &mut dyn Collectable { self } fn as_collectable_with_default_ref(&self) -> &dyn Collectable { self } fn as_collectable_with_default_mut(&mut self) -> &mut dyn Collectable { self } fn take_new_events_until_ts(&mut self, ts_end: u64) -> Box { // TODO improve the search let n1 = self.tss.iter().take_while(|&&x| x <= ts_end).count(); let tss = self.tss.drain(..n1).collect(); let pulses = self.pulses.drain(..n1).collect(); let values = self.values.drain(..n1).collect(); let ret = Self { tss, pulses, values }; Box::new(ret) } fn new_empty_evs(&self) -> Box { Box::new(Self::empty()) } fn drain_into_evs(&mut self, dst: &mut dyn Events, range: (usize, usize)) -> Result<(), MergeError> { // TODO as_any and as_any_mut are declared on unrelated traits. Simplify. if let Some(dst) = dst.as_any_mut().downcast_mut::() { // TODO make it harder to forget new members when the struct may get modified in the future let r = range.0..range.1; dst.tss.extend(self.tss.drain(r.clone())); dst.pulses.extend(self.pulses.drain(r.clone())); dst.values.extend(self.values.drain(r.clone())); Ok(()) } else { error!("downcast to EventsDim0 FAILED"); Err(MergeError::NotCompatible) } } fn find_lowest_index_gt_evs(&self, ts: u64) -> Option { for (i, &m) in self.tss.iter().enumerate() { if m > ts { return Some(i); } } None } fn find_lowest_index_ge_evs(&self, ts: u64) -> Option { for (i, &m) in self.tss.iter().enumerate() { if m >= ts { return Some(i); } } None } fn find_highest_index_lt_evs(&self, ts: u64) -> Option { for (i, &m) in self.tss.iter().enumerate().rev() { if m < ts { return Some(i); } } None } fn ts_min(&self) -> Option { self.tss.front().map(|&x| x) } fn ts_max(&self) -> Option { self.tss.back().map(|&x| x) } fn partial_eq_dyn(&self, other: &dyn Events) -> bool { if let Some(other) = other.as_any_ref().downcast_ref::() { self == other } else { false } } fn serde_id(&self) -> &'static str { Self::serde_id() } fn nty_id(&self) -> u32 { STY::SUB } fn clone_dyn(&self) -> Box { Box::new(self.clone()) } fn tss(&self) -> &VecDeque { &self.tss } fn pulses(&self) -> &VecDeque { &self.pulses } fn frame_type_id(&self) -> u32 { // TODO make more nice panic!() } fn to_min_max_avg(&mut self) -> Box { let mins = self .values .iter() .map(|x| STY::find_vec_min(x)) .map(|x| x.unwrap_or_else(|| STY::zero_b())) .collect(); let maxs = self .values .iter() .map(|x| STY::find_vec_max(x)) .map(|x| x.unwrap_or_else(|| STY::zero_b())) .collect(); let avgs = self .values .iter() .map(|x| STY::avg_vec(x)) .map(|x| x.unwrap_or_else(|| STY::zero_b())) .map(|x| x.as_prim_f32_b()) .collect(); let item = EventsXbinDim0 { tss: mem::replace(&mut self.tss, VecDeque::new()), pulses: mem::replace(&mut self.pulses, VecDeque::new()), mins, maxs, avgs, }; Box::new(item) } fn to_json_string(&self) -> String { let ret = EventsDim1ChunkOutput { // TODO use &mut to swap the content tss: self.tss.clone(), pulses: self.pulses.clone(), values: self.values.clone(), scalar_type: STY::scalar_type_name().into(), }; serde_json::to_string(&ret).unwrap() } fn to_json_vec_u8(&self) -> Vec { self.to_json_string().into_bytes() } fn to_cbor_vec_u8(&self) -> Vec { let ret = EventsDim1ChunkOutput { // TODO use &mut to swap the content tss: self.tss.clone(), pulses: self.pulses.clone(), values: self.values.clone(), scalar_type: STY::scalar_type_name().into(), }; let mut buf = Vec::new(); ciborium::into_writer(&ret, &mut buf).unwrap(); buf } fn clear(&mut self) { self.tss.clear(); self.pulses.clear(); self.values.clear(); } } #[derive(Debug)] pub struct EventsDim1TimeBinner { edges: VecDeque, agg: EventsDim1Aggregator, ready: Option< as TimeBinnableTypeAggregator>::Output>, range_complete: bool, } impl EventsDim1TimeBinner { fn type_name() -> &'static str { any::type_name::() } fn new(binrange: BinnedRangeEnum, do_time_weight: bool) -> Result { /*if edges.len() < 2 { return Err(Error::with_msg_no_trace(format!("need at least 2 edges"))); } let self_name = std::any::type_name::(); trace!("{self_name}::new edges {edges:?}"); let agg = EventsDim1Aggregator::new( NanoRange { beg: edges[0], end: edges[1], }, do_time_weight, ); let ret = Self { edges, agg, ready: None, range_complete: false, }; Ok(ret)*/ // trace!("{}::new binrange {:?}", Self::type_name(), binrange); // let rng = binrange // .range_at(0) // .ok_or_else(|| Error::with_msg_no_trace("empty binrange"))?; // let agg = EventsDim0Aggregator::new(rng, do_time_weight); // let ret = Self { // binrange, // rix: 0, // rng: Some(agg.range().clone()), // agg, // ready: None, // range_final: false, // }; // Ok(ret) todo!() } fn next_bin_range(&mut self) -> Option { /*let self_name = std::any::type_name::(); if self.edges.len() >= 3 { self.edges.pop_front(); let ret = NanoRange { beg: self.edges[0], end: self.edges[1], }; trace!("{self_name} next_bin_range {} {}", ret.beg, ret.end); Some(ret) } else { self.edges.clear(); trace!("{self_name} next_bin_range None"); None }*/ todo!() } } impl TimeBinner for EventsDim1TimeBinner { fn bins_ready_count(&self) -> usize { match &self.ready { Some(k) => k.len(), None => 0, } } fn bins_ready(&mut self) -> Option> { match self.ready.take() { Some(k) => Some(Box::new(k)), None => None, } } fn ingest(&mut self, item: &mut dyn TimeBinnable) { /*let self_name = std::any::type_name::(); trace2!( "TimeBinner for EventsDim1TimeBinner {:?}\n{:?}\n------------------------------------", self.edges.iter().take(2).collect::>(), item ); if item.len() == 0 { // Return already here, RangeOverlapInfo would not give much sense. return; } if self.edges.len() < 2 { warn!("{self_name} no more bin in edges A"); return; } // TODO optimize by remembering at which event array index we have arrived. // That needs modified interfaces which can take and yield the start and latest index. loop { while item.starts_after(self.agg.range().clone()) { trace!("{self_name} IGNORE ITEM AND CYCLE BECAUSE item.starts_after"); self.cycle(); if self.edges.len() < 2 { warn!("{self_name} no more bin in edges B"); return; } } if item.ends_before(self.agg.range().clone()) { trace!("{self_name} IGNORE ITEM BECAUSE ends_before\n------------- -----------"); return; } else { if self.edges.len() < 2 { trace!("{self_name} edge list exhausted"); return; } else { if let Some(item) = item .as_any_ref() // TODO make statically sure that we attempt to cast to the correct type here: .downcast_ref::< as TimeBinnableTypeAggregator>::Input>() { // TODO collect statistics associated with this request: trace!("{self_name} FEED THE ITEM..."); self.agg.ingest(item); if item.ends_after(self.agg.range().clone()) { trace!("{self_name} FED ITEM, ENDS AFTER."); self.cycle(); if self.edges.len() < 2 { warn!("{self_name} no more bin in edges C"); return; } else { trace!("{self_name} FED ITEM, CYCLED, CONTINUE."); } } else { trace!("{self_name} FED ITEM."); break; } } else { panic!("{self_name} not correct item type"); }; } } }*/ todo!() } fn push_in_progress(&mut self, push_empty: bool) { /*let self_name = std::any::type_name::(); trace!("{self_name}::push_in_progress"); // TODO expand should be derived from AggKind. Is it still required after all? // TODO here, the expand means that agg will assume that the current value is kept constant during // the rest of the time range. if self.edges.len() >= 2 { let expand = true; let range_next = if let Some(x) = self.next_bin_range() { Some(x) } else { None }; let mut bins = if let Some(range_next) = range_next { self.agg.result_reset(range_next, expand) } else { let range_next = NanoRange { beg: u64::MAX - 1, end: u64::MAX, }; self.agg.result_reset(range_next, expand) }; assert_eq!(bins.len(), 1); if push_empty || bins.counts[0] != 0 { match self.ready.as_mut() { Some(ready) => { ready.append_all_from(&mut bins); } None => { self.ready = Some(bins); } } } }*/ todo!() } fn cycle(&mut self) { /*let self_name = std::any::type_name::(); trace!("{self_name}::cycle"); // TODO refactor this logic. let n = self.bins_ready_count(); self.push_in_progress(true); if self.bins_ready_count() == n { if let Some(range) = self.next_bin_range() { let mut bins = BinsDim0::::empty(); bins.append_zero(range.beg, range.end); match self.ready.as_mut() { Some(ready) => { ready.append_all_from(&mut bins); } None => { self.ready = Some(bins); } } if self.bins_ready_count() <= n { error!("failed to push a zero bin"); } } else { warn!("cycle: no in-progress bin pushed, but also no more bin to add as zero-bin"); } }*/ todo!() } fn set_range_complete(&mut self) { self.range_complete = true; } fn empty(&self) -> Box { let ret = as TimeBinnableTypeAggregator>::Output::empty(); Box::new(ret) } fn append_empty_until_end(&mut self) { // nothing to do for events } } impl Appendable> for EventsDim1 where STY: ScalarOps, { fn push(&mut self, ts: u64, pulse: u64, value: Vec) { Self::push(self, ts, pulse, value) } }