Move binned type, add tests
This commit is contained in:
@@ -19,6 +19,12 @@ use std::any::Any;
|
||||
use std::collections::VecDeque;
|
||||
use std::{fmt, mem};
|
||||
|
||||
#[allow(unused)]
|
||||
macro_rules! trace4 {
|
||||
($($arg:tt)*) => ();
|
||||
($($arg:tt)*) => (eprintln!($($arg)*));
|
||||
}
|
||||
|
||||
// TODO make members private
|
||||
#[derive(Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct BinsDim0<NTY> {
|
||||
@@ -51,17 +57,6 @@ where
|
||||
}
|
||||
|
||||
impl<NTY: ScalarOps> BinsDim0<NTY> {
|
||||
pub fn empty() -> Self {
|
||||
Self {
|
||||
ts1s: VecDeque::new(),
|
||||
ts2s: VecDeque::new(),
|
||||
counts: VecDeque::new(),
|
||||
mins: VecDeque::new(),
|
||||
maxs: VecDeque::new(),
|
||||
avgs: VecDeque::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push(&mut self, ts1: u64, ts2: u64, count: u64, min: NTY, max: NTY, avg: f32) {
|
||||
self.ts1s.push_back(ts1);
|
||||
self.ts2s.push_back(ts2);
|
||||
@@ -119,6 +114,19 @@ impl<NTY: ScalarOps> BinsDim0<NTY> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<NTY> Empty for BinsDim0<NTY> {
|
||||
fn empty() -> Self {
|
||||
Self {
|
||||
ts1s: VecDeque::new(),
|
||||
ts2s: VecDeque::new(),
|
||||
counts: VecDeque::new(),
|
||||
mins: VecDeque::new(),
|
||||
maxs: VecDeque::new(),
|
||||
avgs: VecDeque::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<NTY> WithLen for BinsDim0<NTY> {
|
||||
fn len(&self) -> usize {
|
||||
self.ts1s.len()
|
||||
@@ -151,19 +159,6 @@ impl<NTY> RangeOverlapInfo for BinsDim0<NTY> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<NTY> Empty for BinsDim0<NTY> {
|
||||
fn empty() -> Self {
|
||||
Self {
|
||||
ts1s: Default::default(),
|
||||
ts2s: Default::default(),
|
||||
counts: Default::default(),
|
||||
mins: Default::default(),
|
||||
maxs: Default::default(),
|
||||
avgs: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<NTY: ScalarOps> AppendEmptyBin for BinsDim0<NTY> {
|
||||
fn append_empty_bin(&mut self, ts1: u64, ts2: u64) {
|
||||
self.ts1s.push_back(ts1);
|
||||
@@ -207,7 +202,8 @@ impl<NTY: ScalarOps> TimeBinnableType for BinsDim0<NTY> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
// TODO rename to BinsDim0CollectorOutput
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct BinsDim0CollectedResult<NTY> {
|
||||
#[serde(rename = "tsAnchor")]
|
||||
ts_anchor_sec: u64,
|
||||
@@ -219,17 +215,23 @@ pub struct BinsDim0CollectedResult<NTY> {
|
||||
ts1_off_ns: VecDeque<u64>,
|
||||
#[serde(rename = "ts2Ns")]
|
||||
ts2_off_ns: VecDeque<u64>,
|
||||
#[serde(rename = "counts")]
|
||||
counts: VecDeque<u64>,
|
||||
#[serde(rename = "mins")]
|
||||
mins: VecDeque<NTY>,
|
||||
#[serde(rename = "maxs")]
|
||||
maxs: VecDeque<NTY>,
|
||||
#[serde(rename = "avgs")]
|
||||
avgs: VecDeque<f32>,
|
||||
#[serde(skip_serializing_if = "crate::bool_is_false", rename = "finalisedRange")]
|
||||
#[serde(rename = "rangeFinal", default, skip_serializing_if = "crate::bool_is_false")]
|
||||
finalised_range: bool,
|
||||
#[serde(skip_serializing_if = "Zero::is_zero", rename = "missingBins")]
|
||||
#[serde(rename = "timedOut", default, skip_serializing_if = "crate::bool_is_false")]
|
||||
timed_out: bool,
|
||||
#[serde(rename = "missingBins", default, skip_serializing_if = "Zero::is_zero")]
|
||||
missing_bins: u32,
|
||||
#[serde(skip_serializing_if = "Option::is_none", rename = "continueAt")]
|
||||
#[serde(rename = "continueAt", default, skip_serializing_if = "Option::is_none")]
|
||||
continue_at: Option<IsoDateTime>,
|
||||
#[serde(skip_serializing_if = "Option::is_none", rename = "finishedAt")]
|
||||
#[serde(rename = "finishedAt", default, skip_serializing_if = "Option::is_none")]
|
||||
finished_at: Option<IsoDateTime>,
|
||||
}
|
||||
|
||||
@@ -242,14 +244,30 @@ impl<NTY: ScalarOps> items_0::AsAnyRef for BinsDim0CollectedResult<NTY> {
|
||||
impl<NTY: ScalarOps> items_0::collect_c::Collected for BinsDim0CollectedResult<NTY> {}
|
||||
|
||||
impl<NTY> BinsDim0CollectedResult<NTY> {
|
||||
pub fn len(&self) -> usize {
|
||||
self.ts1_off_ms.len()
|
||||
}
|
||||
|
||||
pub fn ts_anchor_sec(&self) -> u64 {
|
||||
self.ts_anchor_sec
|
||||
}
|
||||
|
||||
pub fn ts1_off_ms(&self) -> &VecDeque<u64> {
|
||||
&self.ts1_off_ms
|
||||
}
|
||||
|
||||
pub fn ts2_off_ms(&self) -> &VecDeque<u64> {
|
||||
&self.ts2_off_ms
|
||||
}
|
||||
|
||||
pub fn counts(&self) -> &VecDeque<u64> {
|
||||
&self.counts
|
||||
}
|
||||
|
||||
pub fn range_final(&self) -> bool {
|
||||
self.finalised_range
|
||||
}
|
||||
|
||||
pub fn missing_bins(&self) -> u32 {
|
||||
self.missing_bins
|
||||
}
|
||||
@@ -265,6 +283,10 @@ impl<NTY> BinsDim0CollectedResult<NTY> {
|
||||
pub fn maxs(&self) -> &VecDeque<NTY> {
|
||||
&self.maxs
|
||||
}
|
||||
|
||||
pub fn avgs(&self) -> &VecDeque<f32> {
|
||||
&self.avgs
|
||||
}
|
||||
}
|
||||
|
||||
impl<NTY: ScalarOps> ToJsonResult for BinsDim0CollectedResult<NTY> {
|
||||
@@ -278,6 +300,7 @@ impl<NTY: ScalarOps> ToJsonResult for BinsDim0CollectedResult<NTY> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BinsDim0Collector<NTY> {
|
||||
timed_out: bool,
|
||||
range_complete: bool,
|
||||
@@ -305,6 +328,7 @@ impl<NTY: ScalarOps> CollectorType for BinsDim0Collector<NTY> {
|
||||
type Output = BinsDim0CollectedResult<NTY>;
|
||||
|
||||
fn ingest(&mut self, src: &mut Self::Input) {
|
||||
trace!("\n\n----------- BinsDim0Collector ingest\n{:?}\n\n", src);
|
||||
// TODO could be optimized by non-contiguous container.
|
||||
self.vals.ts1s.append(&mut src.ts1s);
|
||||
self.vals.ts2s.append(&mut src.ts2s);
|
||||
@@ -362,6 +386,7 @@ impl<NTY: ScalarOps> CollectorType for BinsDim0Collector<NTY> {
|
||||
maxs,
|
||||
avgs,
|
||||
finalised_range: self.range_complete,
|
||||
timed_out: self.timed_out,
|
||||
missing_bins,
|
||||
continue_at,
|
||||
finished_at,
|
||||
@@ -378,6 +403,73 @@ impl<NTY: ScalarOps> CollectableType for BinsDim0<NTY> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<NTY> items_0::collect_c::Collector for BinsDim0Collector<NTY>
|
||||
where
|
||||
NTY: ScalarOps,
|
||||
{
|
||||
fn len(&self) -> usize {
|
||||
self.vals.len()
|
||||
}
|
||||
|
||||
fn ingest(&mut self, item: &mut dyn items_0::collect_c::Collectable) {
|
||||
trace4!("\n\n••••••••••••••••••••••••••••\nINGEST\n{:?}\n\n", item);
|
||||
{
|
||||
{
|
||||
//let tyid = item.type_id();
|
||||
//let tyid = item.as_any_mut().type_id();
|
||||
//let tyid = format!("{:?}", item.type_id().to_owned());
|
||||
trace4!("ty 0: {:40?}", (item.as_any_mut() as &dyn Any).type_id());
|
||||
}
|
||||
trace4!("ty 1: {:40?}", std::any::TypeId::of::<BinsDim0<NTY>>());
|
||||
trace4!("ty 2: {:40?}", std::any::TypeId::of::<BinsDim0<i32>>());
|
||||
trace4!("ty 3: {:40?}", std::any::TypeId::of::<Box<BinsDim0<i32>>>());
|
||||
trace4!(
|
||||
"ty 4: {:?}",
|
||||
std::any::TypeId::of::<Box<dyn items_0::collect_c::Collectable>>()
|
||||
);
|
||||
trace4!(
|
||||
"ty 5: {:?}",
|
||||
std::any::TypeId::of::<&mut dyn items_0::collect_c::Collectable>()
|
||||
);
|
||||
trace4!("ty 6: {:?}", std::any::TypeId::of::<Box<dyn items_0::TimeBinned>>());
|
||||
}
|
||||
if let Some(item) = item.as_any_mut().downcast_mut::<BinsDim0<NTY>>() {
|
||||
trace4!("ingest plain");
|
||||
CollectorType::ingest(self, item)
|
||||
} else if let Some(item) = item.as_any_mut().downcast_mut::<Box<BinsDim0<NTY>>>() {
|
||||
trace4!("ingest boxed");
|
||||
CollectorType::ingest(self, item)
|
||||
} else if let Some(item) = item.as_any_mut().downcast_mut::<Box<dyn items_0::TimeBinned>>() {
|
||||
trace4!("ingest boxed dyn TimeBinned");
|
||||
if let Some(item) = item.as_any_mut().downcast_mut::<BinsDim0<NTY>>() {
|
||||
trace4!("ingest boxed dyn TimeBinned match");
|
||||
CollectorType::ingest(self, item)
|
||||
} else {
|
||||
warn!("BinsDim0Collector::ingest unexpected inner item");
|
||||
trace!("BinsDim0Collector::ingest unexpected inner item {:?}", item);
|
||||
}
|
||||
} else {
|
||||
warn!("BinsDim0Collector::ingest unexpected item");
|
||||
trace!("BinsDim0Collector::ingest unexpected item {:?}", item);
|
||||
}
|
||||
}
|
||||
|
||||
fn set_range_complete(&mut self) {
|
||||
CollectorType::set_range_complete(self)
|
||||
}
|
||||
|
||||
fn set_timed_out(&mut self) {
|
||||
CollectorType::set_timed_out(self)
|
||||
}
|
||||
|
||||
fn result(&mut self) -> Result<Box<dyn items_0::collect_c::Collected>, Error> {
|
||||
match CollectorType::result(self) {
|
||||
Ok(res) => Ok(Box::new(res)),
|
||||
Err(e) => Err(e.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BinsDim0Aggregator<NTY> {
|
||||
range: NanoRange,
|
||||
count: u64,
|
||||
@@ -510,7 +602,7 @@ impl<NTY: ScalarOps> TimeBinner for BinsDim0TimeBinner<NTY> {
|
||||
return;
|
||||
}
|
||||
if self.edges.len() < 2 {
|
||||
warn!("TimeBinnerDyn for {self_name} no more bin in edges A");
|
||||
warn!("TimeBinnerDyn for {self_name} no more bin in edges A\n{:?}\n\n", item);
|
||||
return;
|
||||
}
|
||||
// TODO optimize by remembering at which event array index we have arrived.
|
||||
@@ -522,7 +614,7 @@ impl<NTY: ScalarOps> TimeBinner for BinsDim0TimeBinner<NTY> {
|
||||
}) {
|
||||
self.cycle();
|
||||
if self.edges.len() < 2 {
|
||||
warn!("TimeBinnerDyn for {self_name} no more bin in edges B");
|
||||
warn!("TimeBinnerDyn for {self_name} no more bin in edges B\n{:?}\n\n", item);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -560,7 +652,7 @@ impl<NTY: ScalarOps> TimeBinner for BinsDim0TimeBinner<NTY> {
|
||||
if item.ends_after(agg.range().clone()) {
|
||||
self.cycle();
|
||||
if self.edges.len() < 2 {
|
||||
warn!("TimeBinnerDyn for {self_name} no more bin in edges C");
|
||||
warn!("TimeBinnerDyn for {self_name} no more bin in edges C\n{:?}\n\n", item);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
@@ -692,3 +784,21 @@ impl<NTY: ScalarOps> TimeBinned for BinsDim0<NTY> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<NTY> items_0::AsAnyMut for BinsDim0<NTY>
|
||||
where
|
||||
NTY: 'static,
|
||||
{
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<NTY> items_0::collect_c::Collectable for BinsDim0<NTY>
|
||||
where
|
||||
NTY: ScalarOps,
|
||||
{
|
||||
fn new_collector(&self) -> Box<dyn items_0::collect_c::Collector> {
|
||||
Box::new(BinsDim0Collector::<NTY>::new())
|
||||
}
|
||||
}
|
||||
|
||||
819
items_2/src/binsxbindim0.rs
Normal file
819
items_2/src/binsxbindim0.rs
Normal file
@@ -0,0 +1,819 @@
|
||||
use crate::{ts_offs_from_abs, ts_offs_from_abs_with_anchor};
|
||||
use crate::{IsoDateTime, RangeOverlapInfo};
|
||||
use crate::{TimeBinnable, TimeBinnableType, TimeBinnableTypeAggregator, TimeBinner};
|
||||
use chrono::{TimeZone, Utc};
|
||||
use err::Error;
|
||||
use items_0::collect_s::{Collectable, CollectableType, CollectorType, ToJsonResult};
|
||||
use items_0::scalar_ops::ScalarOps;
|
||||
use items_0::AppendEmptyBin;
|
||||
use items_0::Empty;
|
||||
use items_0::TimeBinned;
|
||||
use items_0::TimeBins;
|
||||
use items_0::WithLen;
|
||||
use netpod::log::*;
|
||||
use netpod::timeunits::SEC;
|
||||
use netpod::NanoRange;
|
||||
use num_traits::Zero;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::any::Any;
|
||||
use std::collections::VecDeque;
|
||||
use std::{fmt, mem};
|
||||
|
||||
#[allow(unused)]
|
||||
macro_rules! trace4 {
|
||||
($($arg:tt)*) => ();
|
||||
($($arg:tt)*) => (eprintln!($($arg)*));
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct BinsXbinDim0<NTY> {
|
||||
ts1s: VecDeque<u64>,
|
||||
ts2s: VecDeque<u64>,
|
||||
counts: VecDeque<u64>,
|
||||
mins: VecDeque<NTY>,
|
||||
maxs: VecDeque<NTY>,
|
||||
avgs: VecDeque<f32>,
|
||||
// TODO could consider more variables:
|
||||
// ts min/max, pulse min/max, avg of mins, avg of maxs, variances, etc...
|
||||
}
|
||||
|
||||
impl<NTY> fmt::Debug for BinsXbinDim0<NTY>
|
||||
where
|
||||
NTY: fmt::Debug,
|
||||
{
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
let self_name = std::any::type_name::<Self>();
|
||||
write!(
|
||||
fmt,
|
||||
"{self_name} count {} ts1s {:?} ts2s {:?} counts {:?} mins {:?} maxs {:?} avgs {:?}",
|
||||
self.ts1s.len(),
|
||||
self.ts1s.iter().map(|k| k / SEC).collect::<Vec<_>>(),
|
||||
self.ts2s.iter().map(|k| k / SEC).collect::<Vec<_>>(),
|
||||
self.counts,
|
||||
self.mins,
|
||||
self.maxs,
|
||||
self.avgs,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<NTY: ScalarOps> BinsXbinDim0<NTY> {
|
||||
pub fn from_content(
|
||||
ts1s: VecDeque<u64>,
|
||||
ts2s: VecDeque<u64>,
|
||||
counts: VecDeque<u64>,
|
||||
mins: VecDeque<NTY>,
|
||||
maxs: VecDeque<NTY>,
|
||||
avgs: VecDeque<f32>,
|
||||
) -> Self {
|
||||
Self {
|
||||
ts1s,
|
||||
ts2s,
|
||||
counts,
|
||||
mins,
|
||||
maxs,
|
||||
avgs,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push(&mut self, ts1: u64, ts2: u64, count: u64, min: NTY, max: NTY, avg: f32) {
|
||||
self.ts1s.push_back(ts1);
|
||||
self.ts2s.push_back(ts2);
|
||||
self.counts.push_back(count);
|
||||
self.mins.push_back(min);
|
||||
self.maxs.push_back(max);
|
||||
self.avgs.push_back(avg);
|
||||
}
|
||||
|
||||
pub fn append_zero(&mut self, beg: u64, end: u64) {
|
||||
self.ts1s.push_back(beg);
|
||||
self.ts2s.push_back(end);
|
||||
self.counts.push_back(0);
|
||||
self.mins.push_back(NTY::zero_b());
|
||||
self.maxs.push_back(NTY::zero_b());
|
||||
self.avgs.push_back(0.);
|
||||
}
|
||||
|
||||
pub fn append_all_from(&mut self, src: &mut Self) {
|
||||
self.ts1s.extend(src.ts1s.drain(..));
|
||||
self.ts2s.extend(src.ts2s.drain(..));
|
||||
self.counts.extend(src.counts.drain(..));
|
||||
self.mins.extend(src.mins.drain(..));
|
||||
self.maxs.extend(src.maxs.drain(..));
|
||||
self.avgs.extend(src.avgs.drain(..));
|
||||
}
|
||||
|
||||
pub fn equal_slack(&self, other: &Self) -> bool {
|
||||
for (&a, &b) in self.ts1s.iter().zip(other.ts1s.iter()) {
|
||||
if a != b {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (&a, &b) in self.ts2s.iter().zip(other.ts2s.iter()) {
|
||||
if a != b {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (a, b) in self.mins.iter().zip(other.mins.iter()) {
|
||||
if !a.equal_slack(b) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (a, b) in self.maxs.iter().zip(other.maxs.iter()) {
|
||||
if !a.equal_slack(b) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (a, b) in self.avgs.iter().zip(other.avgs.iter()) {
|
||||
if !a.equal_slack(b) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl<NTY> Empty for BinsXbinDim0<NTY> {
|
||||
fn empty() -> Self {
|
||||
Self {
|
||||
ts1s: VecDeque::new(),
|
||||
ts2s: VecDeque::new(),
|
||||
counts: VecDeque::new(),
|
||||
mins: VecDeque::new(),
|
||||
maxs: VecDeque::new(),
|
||||
avgs: VecDeque::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<NTY> WithLen for BinsXbinDim0<NTY> {
|
||||
fn len(&self) -> usize {
|
||||
self.ts1s.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl<NTY> RangeOverlapInfo for BinsXbinDim0<NTY> {
|
||||
fn ends_before(&self, range: NanoRange) -> bool {
|
||||
if let Some(&max) = self.ts2s.back() {
|
||||
max <= range.beg
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
fn ends_after(&self, range: NanoRange) -> bool {
|
||||
if let Some(&max) = self.ts2s.back() {
|
||||
max > range.end
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
fn starts_after(&self, range: NanoRange) -> bool {
|
||||
if let Some(&min) = self.ts1s.front() {
|
||||
min >= range.end
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<NTY: ScalarOps> AppendEmptyBin for BinsXbinDim0<NTY> {
|
||||
fn append_empty_bin(&mut self, ts1: u64, ts2: u64) {
|
||||
self.ts1s.push_back(ts1);
|
||||
self.ts2s.push_back(ts2);
|
||||
self.counts.push_back(0);
|
||||
self.mins.push_back(NTY::zero_b());
|
||||
self.maxs.push_back(NTY::zero_b());
|
||||
self.avgs.push_back(0.);
|
||||
}
|
||||
}
|
||||
|
||||
impl<NTY: ScalarOps> TimeBins for BinsXbinDim0<NTY> {
|
||||
fn ts_min(&self) -> Option<u64> {
|
||||
self.ts1s.front().map(Clone::clone)
|
||||
}
|
||||
|
||||
fn ts_max(&self) -> Option<u64> {
|
||||
self.ts2s.back().map(Clone::clone)
|
||||
}
|
||||
|
||||
fn ts_min_max(&self) -> Option<(u64, u64)> {
|
||||
if let (Some(min), Some(max)) = (self.ts1s.front().map(Clone::clone), self.ts2s.back().map(Clone::clone)) {
|
||||
Some((min, max))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<NTY: ScalarOps> TimeBinnableType for BinsXbinDim0<NTY> {
|
||||
type Output = BinsXbinDim0<NTY>;
|
||||
type Aggregator = BinsXbinDim0Aggregator<NTY>;
|
||||
|
||||
fn aggregator(range: NanoRange, x_bin_count: usize, do_time_weight: bool) -> Self::Aggregator {
|
||||
let self_name = std::any::type_name::<Self>();
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO rename to BinsDim0CollectorOutput
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct BinsXbinDim0CollectedResult<NTY> {
|
||||
#[serde(rename = "tsAnchor")]
|
||||
ts_anchor_sec: u64,
|
||||
#[serde(rename = "ts1Ms")]
|
||||
ts1_off_ms: VecDeque<u64>,
|
||||
#[serde(rename = "ts2Ms")]
|
||||
ts2_off_ms: VecDeque<u64>,
|
||||
#[serde(rename = "ts1Ns")]
|
||||
ts1_off_ns: VecDeque<u64>,
|
||||
#[serde(rename = "ts2Ns")]
|
||||
ts2_off_ns: VecDeque<u64>,
|
||||
#[serde(rename = "counts")]
|
||||
counts: VecDeque<u64>,
|
||||
#[serde(rename = "mins")]
|
||||
mins: VecDeque<NTY>,
|
||||
#[serde(rename = "maxs")]
|
||||
maxs: VecDeque<NTY>,
|
||||
#[serde(rename = "avgs")]
|
||||
avgs: VecDeque<f32>,
|
||||
#[serde(rename = "rangeFinal", default, skip_serializing_if = "crate::bool_is_false")]
|
||||
finalised_range: bool,
|
||||
#[serde(rename = "timedOut", default, skip_serializing_if = "crate::bool_is_false")]
|
||||
timed_out: bool,
|
||||
#[serde(rename = "missingBins", default, skip_serializing_if = "Zero::is_zero")]
|
||||
missing_bins: u32,
|
||||
#[serde(rename = "continueAt", default, skip_serializing_if = "Option::is_none")]
|
||||
continue_at: Option<IsoDateTime>,
|
||||
#[serde(rename = "finishedAt", default, skip_serializing_if = "Option::is_none")]
|
||||
finished_at: Option<IsoDateTime>,
|
||||
}
|
||||
|
||||
impl<NTY: ScalarOps> items_0::AsAnyRef for BinsXbinDim0CollectedResult<NTY> {
|
||||
fn as_any_ref(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<NTY: ScalarOps> items_0::collect_c::Collected for BinsXbinDim0CollectedResult<NTY> {}
|
||||
|
||||
impl<NTY> BinsXbinDim0CollectedResult<NTY> {
|
||||
pub fn len(&self) -> usize {
|
||||
self.ts1_off_ms.len()
|
||||
}
|
||||
|
||||
pub fn ts_anchor_sec(&self) -> u64 {
|
||||
self.ts_anchor_sec
|
||||
}
|
||||
|
||||
pub fn ts1_off_ms(&self) -> &VecDeque<u64> {
|
||||
&self.ts1_off_ms
|
||||
}
|
||||
|
||||
pub fn ts2_off_ms(&self) -> &VecDeque<u64> {
|
||||
&self.ts2_off_ms
|
||||
}
|
||||
|
||||
pub fn counts(&self) -> &VecDeque<u64> {
|
||||
&self.counts
|
||||
}
|
||||
|
||||
pub fn range_final(&self) -> bool {
|
||||
self.finalised_range
|
||||
}
|
||||
|
||||
pub fn missing_bins(&self) -> u32 {
|
||||
self.missing_bins
|
||||
}
|
||||
|
||||
pub fn continue_at(&self) -> Option<IsoDateTime> {
|
||||
self.continue_at.clone()
|
||||
}
|
||||
|
||||
pub fn mins(&self) -> &VecDeque<NTY> {
|
||||
&self.mins
|
||||
}
|
||||
|
||||
pub fn maxs(&self) -> &VecDeque<NTY> {
|
||||
&self.maxs
|
||||
}
|
||||
}
|
||||
|
||||
impl<NTY: ScalarOps> ToJsonResult for BinsXbinDim0CollectedResult<NTY> {
|
||||
fn to_json_result(&self) -> Result<Box<dyn items_0::collect_s::ToJsonBytes>, Error> {
|
||||
let k = serde_json::to_value(self)?;
|
||||
Ok(Box::new(k))
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BinsXbinDim0Collector<NTY> {
|
||||
timed_out: bool,
|
||||
range_complete: bool,
|
||||
vals: BinsXbinDim0<NTY>,
|
||||
}
|
||||
|
||||
impl<NTY> BinsXbinDim0Collector<NTY> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
timed_out: false,
|
||||
range_complete: false,
|
||||
vals: BinsXbinDim0::<NTY>::empty(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<NTY> WithLen for BinsXbinDim0Collector<NTY> {
|
||||
fn len(&self) -> usize {
|
||||
self.vals.ts1s.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl<NTY: ScalarOps> CollectorType for BinsXbinDim0Collector<NTY> {
|
||||
type Input = BinsXbinDim0<NTY>;
|
||||
type Output = BinsXbinDim0CollectedResult<NTY>;
|
||||
|
||||
fn ingest(&mut self, src: &mut Self::Input) {
|
||||
trace!("\n\n----------- BinsXbinDim0Collector ingest\n{:?}\n\n", src);
|
||||
// TODO could be optimized by non-contiguous container.
|
||||
self.vals.ts1s.append(&mut src.ts1s);
|
||||
self.vals.ts2s.append(&mut src.ts2s);
|
||||
self.vals.counts.append(&mut src.counts);
|
||||
self.vals.mins.append(&mut src.mins);
|
||||
self.vals.maxs.append(&mut src.maxs);
|
||||
self.vals.avgs.append(&mut src.avgs);
|
||||
}
|
||||
|
||||
fn set_range_complete(&mut self) {
|
||||
self.range_complete = true;
|
||||
}
|
||||
|
||||
fn set_timed_out(&mut self) {
|
||||
self.timed_out = true;
|
||||
}
|
||||
|
||||
fn result(&mut self) -> Result<Self::Output, Error> {
|
||||
let bin_count_exp = 0;
|
||||
let bin_count = self.vals.ts1s.len() as u32;
|
||||
let (missing_bins, continue_at, finished_at) = if bin_count < bin_count_exp {
|
||||
match self.vals.ts2s.back() {
|
||||
Some(&k) => {
|
||||
let missing_bins = bin_count_exp - bin_count;
|
||||
let continue_at = IsoDateTime(Utc.timestamp_nanos(k as i64));
|
||||
let u = k + (k - self.vals.ts1s.back().unwrap()) * missing_bins as u64;
|
||||
let finished_at = IsoDateTime(Utc.timestamp_nanos(u as i64));
|
||||
(missing_bins, Some(continue_at), Some(finished_at))
|
||||
}
|
||||
None => Err(Error::with_msg("partial_content but no bin in result"))?,
|
||||
}
|
||||
} else {
|
||||
(0, None, None)
|
||||
};
|
||||
if self.vals.ts1s.as_slices().1.len() != 0 {
|
||||
panic!();
|
||||
}
|
||||
if self.vals.ts2s.as_slices().1.len() != 0 {
|
||||
panic!();
|
||||
}
|
||||
let tst1 = ts_offs_from_abs(self.vals.ts1s.as_slices().0);
|
||||
let tst2 = ts_offs_from_abs_with_anchor(tst1.0, self.vals.ts2s.as_slices().0);
|
||||
let counts = mem::replace(&mut self.vals.counts, VecDeque::new());
|
||||
let mins = mem::replace(&mut self.vals.mins, VecDeque::new());
|
||||
let maxs = mem::replace(&mut self.vals.maxs, VecDeque::new());
|
||||
let avgs = mem::replace(&mut self.vals.avgs, VecDeque::new());
|
||||
let ret = BinsXbinDim0CollectedResult::<NTY> {
|
||||
ts_anchor_sec: tst1.0,
|
||||
ts1_off_ms: tst1.1,
|
||||
ts1_off_ns: tst1.2,
|
||||
ts2_off_ms: tst2.0,
|
||||
ts2_off_ns: tst2.1,
|
||||
counts,
|
||||
mins,
|
||||
maxs,
|
||||
avgs,
|
||||
finalised_range: self.range_complete,
|
||||
timed_out: self.timed_out,
|
||||
missing_bins,
|
||||
continue_at,
|
||||
finished_at,
|
||||
};
|
||||
Ok(ret)
|
||||
}
|
||||
}
|
||||
|
||||
impl<NTY: ScalarOps> CollectableType for BinsXbinDim0<NTY> {
|
||||
type Collector = BinsXbinDim0Collector<NTY>;
|
||||
|
||||
fn new_collector() -> Self::Collector {
|
||||
Self::Collector::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<NTY> items_0::collect_c::Collector for BinsXbinDim0Collector<NTY>
|
||||
where
|
||||
NTY: ScalarOps,
|
||||
{
|
||||
fn len(&self) -> usize {
|
||||
self.vals.len()
|
||||
}
|
||||
|
||||
fn ingest(&mut self, item: &mut dyn items_0::collect_c::Collectable) {
|
||||
trace4!("\n\n••••••••••••••••••••••••••••\nINGEST\n{:?}\n\n", item);
|
||||
{
|
||||
{
|
||||
//let tyid = item.type_id();
|
||||
//let tyid = item.as_any_mut().type_id();
|
||||
//let tyid = format!("{:?}", item.type_id().to_owned());
|
||||
trace4!("ty 0: {:40?}", (item.as_any_mut() as &dyn Any).type_id());
|
||||
}
|
||||
trace4!("ty 1: {:40?}", std::any::TypeId::of::<BinsDim0<NTY>>());
|
||||
trace4!("ty 2: {:40?}", std::any::TypeId::of::<BinsDim0<i32>>());
|
||||
trace4!("ty 3: {:40?}", std::any::TypeId::of::<Box<BinsDim0<i32>>>());
|
||||
trace4!(
|
||||
"ty 4: {:?}",
|
||||
std::any::TypeId::of::<Box<dyn items_0::collect_c::Collectable>>()
|
||||
);
|
||||
trace4!(
|
||||
"ty 5: {:?}",
|
||||
std::any::TypeId::of::<&mut dyn items_0::collect_c::Collectable>()
|
||||
);
|
||||
trace4!("ty 6: {:?}", std::any::TypeId::of::<Box<dyn items_0::TimeBinned>>());
|
||||
}
|
||||
if let Some(item) = item.as_any_mut().downcast_mut::<BinsXbinDim0<NTY>>() {
|
||||
trace4!("ingest plain");
|
||||
CollectorType::ingest(self, item)
|
||||
} else if let Some(item) = item.as_any_mut().downcast_mut::<Box<BinsXbinDim0<NTY>>>() {
|
||||
trace4!("ingest boxed");
|
||||
CollectorType::ingest(self, item)
|
||||
} else if let Some(item) = item.as_any_mut().downcast_mut::<Box<dyn items_0::TimeBinned>>() {
|
||||
trace4!("ingest boxed dyn TimeBinned");
|
||||
if let Some(item) = item.as_any_mut().downcast_mut::<BinsXbinDim0<NTY>>() {
|
||||
trace4!("ingest boxed dyn TimeBinned match");
|
||||
CollectorType::ingest(self, item)
|
||||
} else {
|
||||
warn!("BinsDim0Collector::ingest unexpected inner item");
|
||||
trace!("BinsDim0Collector::ingest unexpected inner item {:?}", item);
|
||||
}
|
||||
} else {
|
||||
warn!("BinsDim0Collector::ingest unexpected item");
|
||||
trace!("BinsDim0Collector::ingest unexpected item {:?}", item);
|
||||
}
|
||||
}
|
||||
|
||||
fn set_range_complete(&mut self) {
|
||||
CollectorType::set_range_complete(self)
|
||||
}
|
||||
|
||||
fn set_timed_out(&mut self) {
|
||||
CollectorType::set_timed_out(self)
|
||||
}
|
||||
|
||||
fn result(&mut self) -> Result<Box<dyn items_0::collect_c::Collected>, Error> {
|
||||
match CollectorType::result(self) {
|
||||
Ok(res) => Ok(Box::new(res)),
|
||||
Err(e) => Err(e.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BinsXbinDim0Aggregator<NTY> {
|
||||
range: NanoRange,
|
||||
count: u64,
|
||||
min: NTY,
|
||||
max: NTY,
|
||||
// Carry over to next bin:
|
||||
avg: f32,
|
||||
sumc: u64,
|
||||
sum: f32,
|
||||
}
|
||||
|
||||
impl<NTY: ScalarOps> BinsXbinDim0Aggregator<NTY> {
|
||||
pub fn new(range: NanoRange, _do_time_weight: bool) -> Self {
|
||||
Self {
|
||||
range,
|
||||
count: 0,
|
||||
min: NTY::zero_b(),
|
||||
max: NTY::zero_b(),
|
||||
avg: 0.,
|
||||
sumc: 0,
|
||||
sum: 0f32,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<NTY: ScalarOps> TimeBinnableTypeAggregator for BinsXbinDim0Aggregator<NTY> {
|
||||
type Input = BinsXbinDim0<NTY>;
|
||||
type Output = BinsXbinDim0<NTY>;
|
||||
|
||||
fn range(&self) -> &NanoRange {
|
||||
&self.range
|
||||
}
|
||||
|
||||
fn ingest(&mut self, item: &Self::Input) {
|
||||
for i1 in 0..item.ts1s.len() {
|
||||
if item.counts[i1] == 0 {
|
||||
} else if item.ts2s[i1] <= self.range.beg {
|
||||
} else if item.ts1s[i1] >= self.range.end {
|
||||
} else {
|
||||
if self.count == 0 {
|
||||
self.min = item.mins[i1].clone();
|
||||
self.max = item.maxs[i1].clone();
|
||||
} else {
|
||||
if self.min > item.mins[i1] {
|
||||
self.min = item.mins[i1].clone();
|
||||
}
|
||||
if self.max < item.maxs[i1] {
|
||||
self.max = item.maxs[i1].clone();
|
||||
}
|
||||
}
|
||||
self.count += item.counts[i1];
|
||||
self.sum += item.avgs[i1];
|
||||
self.sumc += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn result_reset(&mut self, range: NanoRange, _expand: bool) -> Self::Output {
|
||||
if self.sumc > 0 {
|
||||
self.avg = self.sum / self.sumc as f32;
|
||||
}
|
||||
let ret = Self::Output {
|
||||
ts1s: [self.range.beg].into(),
|
||||
ts2s: [self.range.end].into(),
|
||||
counts: [self.count].into(),
|
||||
mins: [self.min.clone()].into(),
|
||||
maxs: [self.max.clone()].into(),
|
||||
avgs: [self.avg].into(),
|
||||
};
|
||||
self.range = range;
|
||||
self.count = 0;
|
||||
self.sum = 0f32;
|
||||
self.sumc = 0;
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
impl<NTY: ScalarOps> TimeBinnable for BinsXbinDim0<NTY> {
|
||||
fn time_binner_new(&self, edges: Vec<u64>, do_time_weight: bool) -> Box<dyn TimeBinner> {
|
||||
let ret = BinsXbinDim0TimeBinner::<NTY>::new(edges.into(), do_time_weight);
|
||||
Box::new(ret)
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self as &dyn Any
|
||||
}
|
||||
|
||||
fn to_box_to_json_result(&self) -> Box<dyn ToJsonResult> {
|
||||
let k = serde_json::to_value(self).unwrap();
|
||||
Box::new(k) as _
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BinsXbinDim0TimeBinner<NTY: ScalarOps> {
|
||||
edges: VecDeque<u64>,
|
||||
do_time_weight: bool,
|
||||
agg: Option<BinsXbinDim0Aggregator<NTY>>,
|
||||
ready: Option<<BinsXbinDim0Aggregator<NTY> as TimeBinnableTypeAggregator>::Output>,
|
||||
}
|
||||
|
||||
impl<NTY: ScalarOps> BinsXbinDim0TimeBinner<NTY> {
|
||||
fn new(edges: VecDeque<u64>, do_time_weight: bool) -> Self {
|
||||
Self {
|
||||
edges,
|
||||
do_time_weight,
|
||||
agg: None,
|
||||
ready: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn next_bin_range(&mut self) -> Option<NanoRange> {
|
||||
if self.edges.len() >= 2 {
|
||||
let ret = NanoRange {
|
||||
beg: self.edges[0],
|
||||
end: self.edges[1],
|
||||
};
|
||||
self.edges.pop_front();
|
||||
Some(ret)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<NTY: ScalarOps> TimeBinner for BinsXbinDim0TimeBinner<NTY> {
|
||||
fn ingest(&mut self, item: &dyn TimeBinnable) {
|
||||
let self_name = std::any::type_name::<Self>();
|
||||
if item.len() == 0 {
|
||||
// Return already here, RangeOverlapInfo would not give much sense.
|
||||
return;
|
||||
}
|
||||
if self.edges.len() < 2 {
|
||||
warn!("TimeBinnerDyn for {self_name} no more bin in edges A\n{:?}\n\n", item);
|
||||
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(NanoRange {
|
||||
beg: 0,
|
||||
end: self.edges[1],
|
||||
}) {
|
||||
self.cycle();
|
||||
if self.edges.len() < 2 {
|
||||
warn!("TimeBinnerDyn for {self_name} no more bin in edges B\n{:?}\n\n", item);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if item.ends_before(NanoRange {
|
||||
beg: self.edges[0],
|
||||
end: u64::MAX,
|
||||
}) {
|
||||
return;
|
||||
} else {
|
||||
if self.edges.len() < 2 {
|
||||
warn!("TimeBinnerDyn for {self_name} edge list exhausted");
|
||||
return;
|
||||
} else {
|
||||
let agg = if let Some(agg) = self.agg.as_mut() {
|
||||
agg
|
||||
} else {
|
||||
self.agg = Some(BinsXbinDim0Aggregator::new(
|
||||
// We know here that we have enough edges for another bin.
|
||||
// and `next_bin_range` will pop the first edge.
|
||||
self.next_bin_range().unwrap(),
|
||||
self.do_time_weight,
|
||||
));
|
||||
self.agg.as_mut().unwrap()
|
||||
};
|
||||
if let Some(item) = item
|
||||
.as_any()
|
||||
// TODO make statically sure that we attempt to cast to the correct type here:
|
||||
.downcast_ref::<<BinsXbinDim0Aggregator<NTY> as TimeBinnableTypeAggregator>::Input>()
|
||||
{
|
||||
agg.ingest(item);
|
||||
} else {
|
||||
let tyid_item = std::any::Any::type_id(item.as_any());
|
||||
error!("not correct item type {:?}", tyid_item);
|
||||
};
|
||||
if item.ends_after(agg.range().clone()) {
|
||||
self.cycle();
|
||||
if self.edges.len() < 2 {
|
||||
warn!("TimeBinnerDyn for {self_name} no more bin in edges C\n{:?}\n\n", item);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn bins_ready_count(&self) -> usize {
|
||||
match &self.ready {
|
||||
Some(k) => k.len(),
|
||||
None => 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn bins_ready(&mut self) -> Option<Box<dyn items_0::TimeBinned>> {
|
||||
match self.ready.take() {
|
||||
Some(k) => Some(Box::new(k)),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
// TODO there is too much common code between implementors:
|
||||
fn push_in_progress(&mut self, push_empty: bool) {
|
||||
// TODO expand should be derived from AggKind. Is it still required after all?
|
||||
let expand = true;
|
||||
if let Some(agg) = self.agg.as_mut() {
|
||||
let dummy_range = NanoRange { beg: 4, end: 5 };
|
||||
let mut bins = agg.result_reset(dummy_range, expand);
|
||||
self.agg = None;
|
||||
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 there is too much common code between implementors:
|
||||
fn cycle(&mut self) {
|
||||
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 = BinsXbinDim0::<NTY>::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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn set_range_complete(&mut self) {}
|
||||
}
|
||||
|
||||
impl<NTY: ScalarOps> TimeBinned for BinsXbinDim0<NTY> {
|
||||
fn as_time_binnable_dyn(&self) -> &dyn TimeBinnable {
|
||||
self as &dyn TimeBinnable
|
||||
}
|
||||
|
||||
fn edges_slice(&self) -> (&[u64], &[u64]) {
|
||||
if self.ts1s.as_slices().1.len() != 0 {
|
||||
panic!();
|
||||
}
|
||||
if self.ts2s.as_slices().1.len() != 0 {
|
||||
panic!();
|
||||
}
|
||||
(&self.ts1s.as_slices().0, &self.ts2s.as_slices().0)
|
||||
}
|
||||
|
||||
fn counts(&self) -> &[u64] {
|
||||
// TODO check for contiguous
|
||||
self.counts.as_slices().0
|
||||
}
|
||||
|
||||
// TODO is Vec needed?
|
||||
fn mins(&self) -> Vec<f32> {
|
||||
self.mins.iter().map(|x| x.clone().as_prim_f32_b()).collect()
|
||||
}
|
||||
|
||||
// TODO is Vec needed?
|
||||
fn maxs(&self) -> Vec<f32> {
|
||||
self.maxs.iter().map(|x| x.clone().as_prim_f32_b()).collect()
|
||||
}
|
||||
|
||||
// TODO is Vec needed?
|
||||
fn avgs(&self) -> Vec<f32> {
|
||||
self.avgs.iter().map(Clone::clone).collect()
|
||||
}
|
||||
|
||||
fn validate(&self) -> Result<(), String> {
|
||||
use std::fmt::Write;
|
||||
let mut msg = String::new();
|
||||
if self.ts1s.len() != self.ts2s.len() {
|
||||
write!(&mut msg, "ts1s ≠ ts2s\n").unwrap();
|
||||
}
|
||||
for (i, ((count, min), max)) in self.counts.iter().zip(&self.mins).zip(&self.maxs).enumerate() {
|
||||
if min.as_prim_f32_b() < 1. && *count != 0 {
|
||||
write!(&mut msg, "i {} count {} min {:?} max {:?}\n", i, count, min, max).unwrap();
|
||||
}
|
||||
}
|
||||
if msg.is_empty() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(msg)
|
||||
}
|
||||
}
|
||||
|
||||
fn as_collectable_mut(&mut self) -> &mut dyn Collectable {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<NTY> items_0::AsAnyMut for BinsXbinDim0<NTY>
|
||||
where
|
||||
NTY: 'static,
|
||||
{
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<NTY> items_0::collect_c::Collectable for BinsXbinDim0<NTY>
|
||||
where
|
||||
NTY: ScalarOps,
|
||||
{
|
||||
fn new_collector(&self) -> Box<dyn items_0::collect_c::Collector> {
|
||||
Box::new(BinsXbinDim0Collector::<NTY>::new())
|
||||
}
|
||||
}
|
||||
@@ -110,6 +110,10 @@ mod serde_channel_events {
|
||||
let obj: EventsDim0<f32> = seq.next_element()?.ok_or(de::Error::missing_field("obj .2"))?;
|
||||
Ok(Box::new(obj))
|
||||
}
|
||||
f64::SUB => {
|
||||
let obj: EventsDim0<f64> = seq.next_element()?.ok_or(de::Error::missing_field("obj .2"))?;
|
||||
Ok(Box::new(obj))
|
||||
}
|
||||
_ => Err(de::Error::custom(&format!("unknown nty {e1}"))),
|
||||
}
|
||||
} else {
|
||||
@@ -422,9 +426,6 @@ impl ChannelEventsCollector {
|
||||
}
|
||||
|
||||
impl items_0::collect_c::Collector for ChannelEventsCollector {
|
||||
type Input = ChannelEvents;
|
||||
type Output = Box<dyn items_0::collect_c::Collected>;
|
||||
|
||||
fn len(&self) -> usize {
|
||||
match &self.coll {
|
||||
Some(coll) => coll.len(),
|
||||
@@ -432,19 +433,23 @@ impl items_0::collect_c::Collector for ChannelEventsCollector {
|
||||
}
|
||||
}
|
||||
|
||||
fn ingest(&mut self, item: &mut Self::Input) {
|
||||
match item {
|
||||
ChannelEvents::Events(item) => {
|
||||
if self.coll.is_none() {
|
||||
let coll = item.as_ref().as_collectable_with_default_ref().new_collector();
|
||||
self.coll = Some(coll);
|
||||
fn ingest(&mut self, item: &mut dyn items_0::collect_c::Collectable) {
|
||||
if let Some(item) = item.as_any_mut().downcast_mut::<ChannelEvents>() {
|
||||
match item {
|
||||
ChannelEvents::Events(item) => {
|
||||
if self.coll.is_none() {
|
||||
let coll = item.as_ref().as_collectable_with_default_ref().new_collector();
|
||||
self.coll = Some(coll);
|
||||
}
|
||||
let coll = self.coll.as_mut().unwrap();
|
||||
coll.ingest(item.as_collectable_with_default_mut());
|
||||
}
|
||||
ChannelEvents::Status(_) => {
|
||||
// TODO decide on output format to collect also the connection status events
|
||||
}
|
||||
let coll = self.coll.as_mut().unwrap();
|
||||
coll.ingest(item.as_collectable_with_default_mut());
|
||||
}
|
||||
ChannelEvents::Status(_) => {
|
||||
// TODO decide on output format to collect also the connection status events
|
||||
}
|
||||
} else {
|
||||
error!("ChannelEventsCollector::ingest unexpected item {:?}", item);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -456,7 +461,7 @@ impl items_0::collect_c::Collector for ChannelEventsCollector {
|
||||
self.timed_out = true;
|
||||
}
|
||||
|
||||
fn result(&mut self) -> Result<Self::Output, err::Error> {
|
||||
fn result(&mut self) -> Result<Box<dyn items_0::collect_c::Collected>, err::Error> {
|
||||
match self.coll.as_mut() {
|
||||
Some(coll) => {
|
||||
if self.range_complete {
|
||||
@@ -479,10 +484,14 @@ impl items_0::collect_c::Collector for ChannelEventsCollector {
|
||||
}
|
||||
}
|
||||
|
||||
impl items_0::collect_c::Collectable for ChannelEvents {
|
||||
type Collector = ChannelEventsCollector;
|
||||
|
||||
fn new_collector(&self) -> Self::Collector {
|
||||
ChannelEventsCollector::new()
|
||||
impl items_0::AsAnyMut for ChannelEvents {
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl items_0::collect_c::Collectable for ChannelEvents {
|
||||
fn new_collector(&self) -> Box<dyn items_0::collect_c::Collector> {
|
||||
Box::new(ChannelEventsCollector::new())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use crate::binsdim0::BinsDim0;
|
||||
use crate::{pulse_offs_from_abs, ts_offs_from_abs, RangeOverlapInfo};
|
||||
use crate::{pulse_offs_from_abs, ts_offs_from_abs};
|
||||
use crate::{IsoDateTime, RangeOverlapInfo};
|
||||
use crate::{TimeBinnable, TimeBinnableType, TimeBinnableTypeAggregator, TimeBinner};
|
||||
use err::Error;
|
||||
use items_0::scalar_ops::ScalarOps;
|
||||
@@ -108,7 +109,10 @@ impl<NTY: ScalarOps> RangeOverlapInfo for EventsDim0<NTY> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<NTY: ScalarOps> TimeBinnableType for EventsDim0<NTY> {
|
||||
impl<NTY> TimeBinnableType for EventsDim0<NTY>
|
||||
where
|
||||
NTY: ScalarOps,
|
||||
{
|
||||
type Output = BinsDim0<NTY>;
|
||||
type Aggregator = EventsDim0Aggregator<NTY>;
|
||||
|
||||
@@ -159,10 +163,12 @@ pub struct EventsDim0CollectorOutput<NTY> {
|
||||
pulse_off: VecDeque<u64>,
|
||||
#[serde(rename = "values")]
|
||||
values: VecDeque<NTY>,
|
||||
#[serde(rename = "finalisedRange", default, skip_serializing_if = "crate::bool_is_false")]
|
||||
#[serde(rename = "rangeFinal", default, skip_serializing_if = "crate::bool_is_false")]
|
||||
range_complete: bool,
|
||||
#[serde(rename = "timedOut", default, skip_serializing_if = "crate::bool_is_false")]
|
||||
timed_out: bool,
|
||||
#[serde(rename = "continueAt", default, skip_serializing_if = "Option::is_none")]
|
||||
continue_at: Option<IsoDateTime>,
|
||||
}
|
||||
|
||||
impl<NTY: ScalarOps> EventsDim0CollectorOutput<NTY> {
|
||||
@@ -206,8 +212,6 @@ impl<NTY: ScalarOps> items_0::AsAnyRef for EventsDim0CollectorOutput<NTY> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<NTY: ScalarOps> items_0::collect_c::Collected for EventsDim0CollectorOutput<NTY> {}
|
||||
|
||||
impl<NTY: ScalarOps> items_0::collect_s::ToJsonResult for EventsDim0CollectorOutput<NTY> {
|
||||
fn to_json_result(&self) -> Result<Box<dyn items_0::collect_s::ToJsonBytes>, Error> {
|
||||
let k = serde_json::to_value(self)?;
|
||||
@@ -219,12 +223,13 @@ impl<NTY: ScalarOps> items_0::collect_s::ToJsonResult for EventsDim0CollectorOut
|
||||
}
|
||||
}
|
||||
|
||||
impl<NTY: ScalarOps> items_0::collect_c::Collected for EventsDim0CollectorOutput<NTY> {}
|
||||
|
||||
impl<NTY: ScalarOps> items_0::collect_s::CollectorType for EventsDim0Collector<NTY> {
|
||||
type Input = EventsDim0<NTY>;
|
||||
type Output = EventsDim0CollectorOutput<NTY>;
|
||||
|
||||
fn ingest(&mut self, src: &mut Self::Input) {
|
||||
// TODO could be optimized by non-contiguous container.
|
||||
self.vals.tss.append(&mut src.tss);
|
||||
self.vals.pulses.append(&mut src.pulses);
|
||||
self.vals.values.append(&mut src.values);
|
||||
@@ -239,18 +244,38 @@ impl<NTY: ScalarOps> items_0::collect_s::CollectorType for EventsDim0Collector<N
|
||||
}
|
||||
|
||||
fn result(&mut self) -> Result<Self::Output, Error> {
|
||||
// TODO require contiguous slices
|
||||
let tst = ts_offs_from_abs(&self.vals.tss.as_slices().0);
|
||||
let (pulse_anchor, pulse_off) = pulse_offs_from_abs(&self.vals.pulses.as_slices().0);
|
||||
// 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 continue_at = if self.timed_out {
|
||||
if let Some(ts) = self.vals.tss.back() {
|
||||
Some(IsoDateTime::from_u64(*ts))
|
||||
} else {
|
||||
// TODO tricky: should yield again the original range begin? Leads to recursion.
|
||||
// Range begin plus delta?
|
||||
// Anyway, we don't have the range begin here.
|
||||
warn!("timed out without any result, can not yield a continue-at");
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let tss_sl = self.vals.tss.make_contiguous();
|
||||
let pulses_sl = self.vals.pulses.make_contiguous();
|
||||
let (ts_anchor_sec, ts_off_ms, ts_off_ns) = ts_offs_from_abs(tss_sl);
|
||||
let (pulse_anchor, pulse_off) = pulse_offs_from_abs(pulses_sl);
|
||||
let ret = Self::Output {
|
||||
ts_anchor_sec: tst.0,
|
||||
ts_off_ms: tst.1,
|
||||
ts_off_ns: tst.2,
|
||||
ts_anchor_sec,
|
||||
ts_off_ms,
|
||||
ts_off_ns,
|
||||
pulse_anchor,
|
||||
pulse_off: pulse_off,
|
||||
values: mem::replace(&mut self.vals.values, VecDeque::new()),
|
||||
range_complete: self.range_complete,
|
||||
timed_out: self.timed_out,
|
||||
continue_at,
|
||||
};
|
||||
Ok(ret)
|
||||
}
|
||||
@@ -265,15 +290,16 @@ impl<NTY: ScalarOps> items_0::collect_s::CollectableType for EventsDim0<NTY> {
|
||||
}
|
||||
|
||||
impl<NTY: ScalarOps> items_0::collect_c::Collector for EventsDim0Collector<NTY> {
|
||||
type Input = EventsDim0<NTY>;
|
||||
type Output = EventsDim0CollectorOutput<NTY>;
|
||||
|
||||
fn len(&self) -> usize {
|
||||
self.vals.len()
|
||||
}
|
||||
|
||||
fn ingest(&mut self, item: &mut Self::Input) {
|
||||
items_0::collect_s::CollectorType::ingest(self, item)
|
||||
fn ingest(&mut self, item: &mut dyn items_0::collect_c::Collectable) {
|
||||
if let Some(item) = item.as_any_mut().downcast_mut::<EventsDim0<NTY>>() {
|
||||
items_0::collect_s::CollectorType::ingest(self, item)
|
||||
} else {
|
||||
error!("EventsDim0Collector::ingest unexpected item {:?}", item);
|
||||
}
|
||||
}
|
||||
|
||||
fn set_range_complete(&mut self) {
|
||||
@@ -284,8 +310,11 @@ impl<NTY: ScalarOps> items_0::collect_c::Collector for EventsDim0Collector<NTY>
|
||||
items_0::collect_s::CollectorType::set_timed_out(self)
|
||||
}
|
||||
|
||||
fn result(&mut self) -> Result<Self::Output, err::Error> {
|
||||
items_0::collect_s::CollectorType::result(self).map_err(Into::into)
|
||||
fn result(&mut self) -> Result<Box<dyn items_0::collect_c::Collected>, err::Error> {
|
||||
match items_0::collect_s::CollectorType::result(self) {
|
||||
Ok(x) => Ok(Box::new(x)),
|
||||
Err(e) => Err(e.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -888,6 +917,7 @@ impl<NTY: ScalarOps> TimeBinner for EventsDim0TimeBinner<NTY> {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO remove this struct?
|
||||
#[derive(Debug)]
|
||||
pub struct EventsDim0CollectorDyn {}
|
||||
|
||||
@@ -903,7 +933,6 @@ impl items_0::collect_c::CollectorDyn for EventsDim0CollectorDyn {
|
||||
}
|
||||
|
||||
fn ingest(&mut self, _item: &mut dyn items_0::collect_c::CollectableWithDefault) {
|
||||
// TODO remove this struct?
|
||||
todo!()
|
||||
}
|
||||
|
||||
@@ -961,10 +990,14 @@ impl<NTY: ScalarOps> items_0::collect_c::CollectableWithDefault for EventsDim0<N
|
||||
}
|
||||
}
|
||||
|
||||
impl<NTY: ScalarOps> items_0::collect_c::Collectable for EventsDim0<NTY> {
|
||||
type Collector = EventsDim0Collector<NTY>;
|
||||
|
||||
fn new_collector(&self) -> Self::Collector {
|
||||
EventsDim0Collector::new()
|
||||
impl<NTY: ScalarOps> items_0::AsAnyMut for EventsDim0<NTY> {
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<NTY: ScalarOps> items_0::collect_c::Collectable for EventsDim0<NTY> {
|
||||
fn new_collector(&self) -> Box<dyn items_0::collect_c::Collector> {
|
||||
Box::new(EventsDim0Collector::<NTY>::new())
|
||||
}
|
||||
}
|
||||
|
||||
498
items_2/src/eventsxbindim0.rs
Normal file
498
items_2/src/eventsxbindim0.rs
Normal file
@@ -0,0 +1,498 @@
|
||||
use crate::binsxbindim0::BinsXbinDim0;
|
||||
use crate::RangeOverlapInfo;
|
||||
use crate::{pulse_offs_from_abs, ts_offs_from_abs};
|
||||
use crate::{TimeBinnableType, TimeBinnableTypeAggregator};
|
||||
use err::Error;
|
||||
use items_0::scalar_ops::ScalarOps;
|
||||
use items_0::Empty;
|
||||
use items_0::WithLen;
|
||||
use netpod::log::*;
|
||||
use netpod::NanoRange;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::any::Any;
|
||||
use std::collections::VecDeque;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct EventsXbinDim0<NTY> {
|
||||
pub tss: VecDeque<u64>,
|
||||
pub pulses: VecDeque<u64>,
|
||||
pub mins: VecDeque<NTY>,
|
||||
pub maxs: VecDeque<NTY>,
|
||||
pub avgs: VecDeque<f32>,
|
||||
// TODO maybe add variance?
|
||||
}
|
||||
|
||||
impl<NTY> EventsXbinDim0<NTY> {
|
||||
#[inline(always)]
|
||||
pub fn push(&mut self, ts: u64, pulse: u64, min: NTY, max: NTY, avg: f32) {
|
||||
self.tss.push_back(ts);
|
||||
self.pulses.push_back(pulse);
|
||||
self.mins.push_back(min);
|
||||
self.maxs.push_back(max);
|
||||
self.avgs.push_back(avg);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn push_front(&mut self, ts: u64, pulse: u64, min: NTY, max: NTY, avg: f32) {
|
||||
self.tss.push_front(ts);
|
||||
self.pulses.push_front(pulse);
|
||||
self.mins.push_front(min);
|
||||
self.maxs.push_front(max);
|
||||
self.avgs.push_front(avg);
|
||||
}
|
||||
}
|
||||
|
||||
impl<NTY> fmt::Debug for EventsXbinDim0<NTY>
|
||||
where
|
||||
NTY: fmt::Debug,
|
||||
{
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt.debug_struct("EventsXbinDim0")
|
||||
.field("tss", &self.tss)
|
||||
.field("pulses", &self.pulses)
|
||||
.field("mins", &self.mins)
|
||||
.field("maxs", &self.maxs)
|
||||
.field("avgs", &self.avgs)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<NTY> items::ByteEstimate for EventsXbinDim0<NTY> {
|
||||
fn byte_estimate(&self) -> u64 {
|
||||
todo!("byte_estimate")
|
||||
}
|
||||
}
|
||||
|
||||
impl<NTY> Empty for EventsXbinDim0<NTY> {
|
||||
fn empty() -> Self {
|
||||
Self {
|
||||
tss: VecDeque::new(),
|
||||
pulses: VecDeque::new(),
|
||||
mins: VecDeque::new(),
|
||||
maxs: VecDeque::new(),
|
||||
avgs: VecDeque::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<NTY> WithLen for EventsXbinDim0<NTY> {
|
||||
fn len(&self) -> usize {
|
||||
self.tss.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl<NTY> RangeOverlapInfo for EventsXbinDim0<NTY> {
|
||||
fn ends_before(&self, range: NanoRange) -> bool {
|
||||
match self.tss.back() {
|
||||
Some(&ts) => ts < range.beg,
|
||||
None => true,
|
||||
}
|
||||
}
|
||||
|
||||
fn ends_after(&self, range: NanoRange) -> bool {
|
||||
match self.tss.back() {
|
||||
Some(&ts) => ts >= range.end,
|
||||
None => panic!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn starts_after(&self, range: NanoRange) -> bool {
|
||||
match self.tss.front() {
|
||||
Some(&ts) => ts >= range.end,
|
||||
None => panic!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<NTY> TimeBinnableType for EventsXbinDim0<NTY>
|
||||
where
|
||||
NTY: ScalarOps,
|
||||
{
|
||||
type Output = BinsXbinDim0<NTY>;
|
||||
type Aggregator = EventsXbinDim0Aggregator<NTY>;
|
||||
|
||||
fn aggregator(range: NanoRange, x_bin_count: usize, do_time_weight: bool) -> Self::Aggregator {
|
||||
let name = std::any::type_name::<Self>();
|
||||
debug!(
|
||||
"TimeBinnableType for {} aggregator() range {:?} x_bin_count {} do_time_weight {}",
|
||||
name, range, x_bin_count, do_time_weight
|
||||
);
|
||||
Self::Aggregator::new(range, do_time_weight)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EventsXbinDim0Aggregator<NTY>
|
||||
where
|
||||
NTY: ScalarOps,
|
||||
{
|
||||
range: NanoRange,
|
||||
count: u64,
|
||||
min: NTY,
|
||||
max: NTY,
|
||||
sumc: u64,
|
||||
sum: f32,
|
||||
int_ts: u64,
|
||||
last_ts: u64,
|
||||
last_avg: Option<f32>,
|
||||
last_min: Option<NTY>,
|
||||
last_max: Option<NTY>,
|
||||
do_time_weight: bool,
|
||||
}
|
||||
|
||||
impl<NTY> EventsXbinDim0Aggregator<NTY>
|
||||
where
|
||||
NTY: ScalarOps,
|
||||
{
|
||||
pub fn new(range: NanoRange, do_time_weight: bool) -> Self {
|
||||
Self {
|
||||
int_ts: range.beg,
|
||||
range,
|
||||
count: 0,
|
||||
min: NTY::zero_b(),
|
||||
max: NTY::zero_b(),
|
||||
sumc: 0,
|
||||
sum: 0f32,
|
||||
last_ts: 0,
|
||||
last_avg: None,
|
||||
last_min: None,
|
||||
last_max: None,
|
||||
do_time_weight,
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_min_max(&mut self, min: NTY, max: NTY) {
|
||||
if self.count == 0 {
|
||||
self.min = min;
|
||||
self.max = max;
|
||||
} else {
|
||||
if min < self.min {
|
||||
self.min = min;
|
||||
}
|
||||
if max > self.max {
|
||||
self.max = max;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_event_unweight(&mut self, avg: f32, min: NTY, max: NTY) {
|
||||
//debug!("apply_event_unweight");
|
||||
self.apply_min_max(min, max);
|
||||
let vf = avg;
|
||||
if vf.is_nan() {
|
||||
} else {
|
||||
self.sum += vf;
|
||||
self.sumc += 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_event_time_weight(&mut self, ts: u64) {
|
||||
//debug!("apply_event_time_weight");
|
||||
if let (Some(avg), Some(min), Some(max)) = (self.last_avg, &self.last_min, &self.last_max) {
|
||||
let min2 = min.clone();
|
||||
let max2 = max.clone();
|
||||
self.apply_min_max(min2, max2);
|
||||
let w = (ts - self.int_ts) as f32 / self.range.delta() as f32;
|
||||
if avg.is_nan() {
|
||||
} else {
|
||||
self.sum += avg * w;
|
||||
}
|
||||
self.sumc += 1;
|
||||
self.int_ts = ts;
|
||||
}
|
||||
}
|
||||
|
||||
fn ingest_unweight(&mut self, item: &EventsXbinDim0<NTY>) {
|
||||
for i1 in 0..item.tss.len() {
|
||||
let ts = item.tss[i1];
|
||||
let avg = item.avgs[i1];
|
||||
let min = item.mins[i1].clone();
|
||||
let max = item.maxs[i1].clone();
|
||||
if ts < self.range.beg {
|
||||
} else if ts >= self.range.end {
|
||||
} else {
|
||||
self.apply_event_unweight(avg, min, max);
|
||||
self.count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn ingest_time_weight(&mut self, item: &EventsXbinDim0<NTY>) {
|
||||
for i1 in 0..item.tss.len() {
|
||||
let ts = item.tss[i1];
|
||||
let avg = item.avgs[i1];
|
||||
let min = item.mins[i1].clone();
|
||||
let max = item.maxs[i1].clone();
|
||||
if ts < self.int_ts {
|
||||
self.last_ts = ts;
|
||||
self.last_avg = Some(avg);
|
||||
self.last_min = Some(min);
|
||||
self.last_max = Some(max);
|
||||
} else if ts >= self.range.end {
|
||||
return;
|
||||
} else {
|
||||
self.apply_event_time_weight(ts);
|
||||
self.count += 1;
|
||||
self.last_ts = ts;
|
||||
self.last_avg = Some(avg);
|
||||
self.last_min = Some(min);
|
||||
self.last_max = Some(max);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn result_reset_unweight(&mut self, range: NanoRange, _expand: bool) -> BinsXbinDim0<NTY> {
|
||||
let avg = if self.sumc == 0 {
|
||||
0f32
|
||||
} else {
|
||||
self.sum / self.sumc as f32
|
||||
};
|
||||
let ret = BinsXbinDim0::from_content(
|
||||
[self.range.beg].into(),
|
||||
[self.range.end].into(),
|
||||
[self.count].into(),
|
||||
[self.min.clone()].into(),
|
||||
[self.max.clone()].into(),
|
||||
[avg].into(),
|
||||
);
|
||||
self.int_ts = range.beg;
|
||||
self.range = range;
|
||||
self.count = 0;
|
||||
self.min = NTY::zero_b();
|
||||
self.max = NTY::zero_b();
|
||||
self.sum = 0f32;
|
||||
self.sumc = 0;
|
||||
ret
|
||||
}
|
||||
|
||||
fn result_reset_time_weight(&mut self, range: NanoRange, expand: bool) -> BinsXbinDim0<NTY> {
|
||||
// TODO check callsite for correct expand status.
|
||||
if true || expand {
|
||||
self.apply_event_time_weight(self.range.end);
|
||||
}
|
||||
let avg = {
|
||||
let sc = self.range.delta() as f32 * 1e-9;
|
||||
self.sum / sc
|
||||
};
|
||||
let ret = BinsXbinDim0::from_content(
|
||||
[self.range.beg].into(),
|
||||
[self.range.end].into(),
|
||||
[self.count].into(),
|
||||
[self.min.clone()].into(),
|
||||
[self.max.clone()].into(),
|
||||
[avg].into(),
|
||||
);
|
||||
self.int_ts = range.beg;
|
||||
self.range = range;
|
||||
self.count = 0;
|
||||
self.min = NTY::zero_b();
|
||||
self.max = NTY::zero_b();
|
||||
self.sum = 0f32;
|
||||
self.sumc = 0;
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
impl<NTY> TimeBinnableTypeAggregator for EventsXbinDim0Aggregator<NTY>
|
||||
where
|
||||
NTY: ScalarOps,
|
||||
{
|
||||
type Input = EventsXbinDim0<NTY>;
|
||||
type Output = BinsXbinDim0<NTY>;
|
||||
|
||||
fn range(&self) -> &NanoRange {
|
||||
&self.range
|
||||
}
|
||||
|
||||
fn ingest(&mut self, item: &Self::Input) {
|
||||
debug!("ingest");
|
||||
if self.do_time_weight {
|
||||
self.ingest_time_weight(item)
|
||||
} else {
|
||||
self.ingest_unweight(item)
|
||||
}
|
||||
}
|
||||
|
||||
fn result_reset(&mut self, range: NanoRange, expand: bool) -> Self::Output {
|
||||
if self.do_time_weight {
|
||||
self.result_reset_time_weight(range, expand)
|
||||
} else {
|
||||
self.result_reset_unweight(range, expand)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct EventsXbinDim0CollectorOutput<NTY> {
|
||||
#[serde(rename = "tsAnchor")]
|
||||
ts_anchor_sec: u64,
|
||||
#[serde(rename = "tsMs")]
|
||||
ts_off_ms: VecDeque<u64>,
|
||||
#[serde(rename = "tsNs")]
|
||||
ts_off_ns: VecDeque<u64>,
|
||||
#[serde(rename = "pulseAnchor")]
|
||||
pulse_anchor: u64,
|
||||
#[serde(rename = "pulseOff")]
|
||||
pulse_off: VecDeque<u64>,
|
||||
#[serde(rename = "mins")]
|
||||
mins: VecDeque<NTY>,
|
||||
#[serde(rename = "maxs")]
|
||||
maxs: VecDeque<NTY>,
|
||||
#[serde(rename = "avgs")]
|
||||
avgs: VecDeque<f32>,
|
||||
#[serde(rename = "rangeFinal", default, skip_serializing_if = "crate::bool_is_false")]
|
||||
finalised_range: bool,
|
||||
#[serde(rename = "timedOut", default, skip_serializing_if = "crate::bool_is_false")]
|
||||
timed_out: bool,
|
||||
// TODO add continue-at
|
||||
}
|
||||
|
||||
impl<NTY> items_0::AsAnyRef for EventsXbinDim0CollectorOutput<NTY>
|
||||
where
|
||||
NTY: ScalarOps,
|
||||
{
|
||||
fn as_any_ref(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<NTY> items_0::collect_s::ToJsonResult for EventsXbinDim0CollectorOutput<NTY>
|
||||
where
|
||||
NTY: ScalarOps,
|
||||
{
|
||||
fn to_json_result(&self) -> Result<Box<dyn items_0::collect_s::ToJsonBytes>, Error> {
|
||||
let k = serde_json::to_value(self)?;
|
||||
Ok(Box::new(k))
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<NTY> items_0::collect_c::Collected for EventsXbinDim0CollectorOutput<NTY> where NTY: ScalarOps {}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct EventsXbinDim0Collector<NTY> {
|
||||
vals: EventsXbinDim0<NTY>,
|
||||
finalised_range: bool,
|
||||
timed_out: bool,
|
||||
}
|
||||
|
||||
impl<NTY> EventsXbinDim0Collector<NTY> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
finalised_range: false,
|
||||
timed_out: false,
|
||||
vals: EventsXbinDim0::empty(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<NTY> WithLen for EventsXbinDim0Collector<NTY> {
|
||||
fn len(&self) -> usize {
|
||||
self.vals.tss.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl<NTY> items_0::collect_s::CollectorType for EventsXbinDim0Collector<NTY>
|
||||
where
|
||||
NTY: ScalarOps,
|
||||
{
|
||||
type Input = EventsXbinDim0<NTY>;
|
||||
type Output = EventsXbinDim0CollectorOutput<NTY>;
|
||||
|
||||
fn ingest(&mut self, src: &mut Self::Input) {
|
||||
self.vals.tss.append(&mut src.tss);
|
||||
self.vals.pulses.append(&mut src.pulses);
|
||||
self.vals.mins.append(&mut src.mins);
|
||||
self.vals.maxs.append(&mut src.maxs);
|
||||
self.vals.avgs.append(&mut src.avgs);
|
||||
}
|
||||
|
||||
fn set_range_complete(&mut self) {
|
||||
self.finalised_range = true;
|
||||
}
|
||||
|
||||
fn set_timed_out(&mut self) {
|
||||
self.timed_out = true;
|
||||
}
|
||||
|
||||
fn result(&mut self) -> Result<Self::Output, Error> {
|
||||
use std::mem::replace;
|
||||
let mins = replace(&mut self.vals.mins, VecDeque::new());
|
||||
let maxs = replace(&mut self.vals.maxs, VecDeque::new());
|
||||
let avgs = replace(&mut self.vals.avgs, VecDeque::new());
|
||||
self.vals.tss.make_contiguous();
|
||||
self.vals.pulses.make_contiguous();
|
||||
let tst = ts_offs_from_abs(self.vals.tss.as_slices().0);
|
||||
let (pulse_anchor, pulse_off) = pulse_offs_from_abs(&self.vals.pulses.as_slices().0);
|
||||
let ret = Self::Output {
|
||||
ts_anchor_sec: tst.0,
|
||||
ts_off_ms: tst.1,
|
||||
ts_off_ns: tst.2,
|
||||
pulse_anchor,
|
||||
pulse_off,
|
||||
mins,
|
||||
maxs,
|
||||
avgs,
|
||||
finalised_range: self.finalised_range,
|
||||
timed_out: self.timed_out,
|
||||
};
|
||||
Ok(ret)
|
||||
}
|
||||
}
|
||||
|
||||
impl<NTY> items_0::collect_s::CollectableType for EventsXbinDim0<NTY>
|
||||
where
|
||||
NTY: ScalarOps,
|
||||
{
|
||||
type Collector = EventsXbinDim0Collector<NTY>;
|
||||
|
||||
fn new_collector() -> Self::Collector {
|
||||
Self::Collector::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<NTY> items_0::AsAnyMut for EventsXbinDim0<NTY>
|
||||
where
|
||||
NTY: ScalarOps,
|
||||
{
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<NTY> items_0::collect_c::Collector for EventsXbinDim0Collector<NTY>
|
||||
where
|
||||
NTY: ScalarOps,
|
||||
{
|
||||
fn len(&self) -> usize {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn ingest(&mut self, _item: &mut dyn items_0::collect_c::Collectable) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn set_range_complete(&mut self) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn set_timed_out(&mut self) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn result(&mut self) -> Result<Box<dyn items_0::collect_c::Collected>, Error> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<NTY> items_0::collect_c::Collectable for EventsXbinDim0<NTY>
|
||||
where
|
||||
NTY: ScalarOps,
|
||||
{
|
||||
fn new_collector(&self) -> Box<dyn items_0::collect_c::Collector> {
|
||||
Box::new(<Self as items_0::collect_s::CollectableType>::new_collector())
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
pub mod binsdim0;
|
||||
pub mod binsxbindim0;
|
||||
pub mod channelevents;
|
||||
pub mod eventsdim0;
|
||||
pub mod eventsxbindim0;
|
||||
pub mod merger;
|
||||
pub mod merger_cev;
|
||||
pub mod streams;
|
||||
@@ -138,6 +140,12 @@ impl serde::de::Error for Error {
|
||||
#[derive(Clone, Debug, PartialEq, Deserialize)]
|
||||
pub struct IsoDateTime(DateTime<Utc>);
|
||||
|
||||
impl IsoDateTime {
|
||||
pub fn from_u64(ts: u64) -> Self {
|
||||
IsoDateTime(Utc.timestamp_nanos(ts as i64))
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for IsoDateTime {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
@@ -182,6 +190,7 @@ impl crate::merger::Mergeable for Box<dyn Events> {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO rename to `Typed`
|
||||
pub trait TimeBinnableType: Send + Unpin + RangeOverlapInfo {
|
||||
type Output: TimeBinnableType;
|
||||
type Aggregator: TimeBinnableTypeAggregator<Input = Self, Output = Self::Output> + Send + Unpin;
|
||||
|
||||
Reference in New Issue
Block a user