use std::collections::{BTreeSet, HashMap};
use std::hash::Hash;
use crate::data_model::{EventType, Timestamped};
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
pub struct EventStreamStore<Device: Eq + Clone + Hash, Event: Ord + Clone> {
events: HashMap<Device, BTreeSet<Event>>,
}
impl<Device: Eq + Clone + Hash, Event: Ord + Clone> EventStreamStore<Device, Event> {
pub fn events(&self) -> &HashMap<Device, BTreeSet<Event>> {
&self.events
}
}
impl<Device: Eq + Hash + Clone, Event: Ord + Clone> Default for EventStreamStore<Device, Event> {
fn default() -> Self {
Self {
events: HashMap::new(),
}
}
}
impl<Device: Eq + Hash + Clone, Event: Ord + Clone> EventStreamStore<Device, Timestamped<Event>> {
pub fn len_device(&self, device: &Device) -> usize {
self.events.get(device).map(|set| set.len()).unwrap_or(0)
}
pub(crate) fn valid_to_add_events<A>(
&self,
key: &Device,
mut events: Vec<Timestamped<A>>,
) -> Option<ValidToAddEvents<Timestamped<A>>> {
if events.is_empty() {
return None;
}
events.sort_by_key(|event| event.within_device_events_index);
for i in 0..events.len() - 1 {
if events[i].within_device_events_index + 1 != events[i + 1].within_device_events_index
{
log::warn!("Gap detected in events");
return None;
}
}
let expected_index = self.events().get(key).map(BTreeSet::len).unwrap_or(0);
if events[0].within_device_events_index != expected_index {
log::warn!(
"Event out of order - expected index {}, got {}",
expected_index,
events[0].within_device_events_index
);
return None;
}
Some(ValidToAddEvents { events })
}
pub(crate) fn add_device_events(
&mut self,
key: Device,
events: ValidToAddEvents<Timestamped<Event>>,
) -> usize {
let mut events_added = 0;
let Some(events) = self.valid_to_add_events(&key, events.events) else {
return events_added;
};
let stream = self.events.entry(key.clone()).or_default();
for event in events.events {
events_added += 1;
stream.insert(event);
}
events_added
}
}
impl<K: Eq + Hash + Clone, T: Ord + Clone> EventStreamStore<K, T> {
#[allow(unused)]
pub fn add_event_unchecked(&mut self, key: K, event: T) {
self.events.entry(key).or_default().insert(event);
}
pub fn iter(&self) -> impl Iterator<Item = &T> {
let mut iters: Vec<_> = self
.events
.values()
.map(|set| set.iter().peekable())
.collect();
std::iter::from_fn(move || {
let mut min_idx = None;
let mut min_val = None;
for (idx, iter) in iters.iter_mut().enumerate() {
if let Some(val) = iter.peek() {
if min_val.is_none() || val < min_val.unwrap() {
min_idx = Some(idx);
min_val = Some(val);
}
}
}
if let Some(idx) = min_idx {
iters[idx].next()
} else {
None
}
})
}
pub fn num_events(&self) -> usize {
self.events.values().flatten().count()
}
#[allow(unused)]
pub fn map<U: Ord + Clone>(self, f: impl Fn(T) -> U + Clone) -> EventStreamStore<K, U> {
EventStreamStore {
events: self
.events
.into_iter()
.map(|(k, vs)| (k, vs.into_iter().map(f.clone()).collect::<BTreeSet<U>>()))
.collect(),
}
}
}
impl<Device: Eq + Hash + Clone, Event: Ord + Clone + crate::Event>
EventStreamStore<Device, Timestamped<EventType<Event>>>
{
pub fn state<A>(&self, initial_state: A::Partial) -> A
where
A: crate::PartialAppState<Event = Event>,
{
apply_events_and_metaevents(self.iter(), initial_state)
}
}
pub(crate) fn apply_events_and_metaevents<'a, E: crate::data_model::Event + 'a, A>(
events: impl Iterator<Item = &'a Timestamped<EventType<E>>>,
initial_state: A::Partial,
) -> A
where
A: crate::PartialAppState<Event = E>,
{
let events = events
.cloned()
.filter_map(|event| match event {
Timestamped {
event: EventType::User(event),
timestamp,
within_device_events_index,
} => Some(Timestamped {
event,
timestamp,
within_device_events_index,
}),
_ => unimplemented!(), })
.collect::<Vec<_>>();
apply_events(events.iter(), initial_state)
}
pub(crate) fn apply_events<'a, E: crate::data_model::Event + 'a, A>(
events: impl Iterator<Item = &'a Timestamped<E>>,
initial_state: A::Partial,
) -> A
where
A: crate::PartialAppState<Event = E>,
{
let mut state = initial_state;
for event in events {
state = A::process_event(state, event);
}
A::finalize(state)
}
pub struct ValidToAddEvents<Event> {
events: Vec<Event>,
}
impl<Event> ValidToAddEvents<Timestamped<Event>> {
pub(crate) fn try_map<A, Error, F: Fn(Event) -> Result<A, Error>>(
self,
f: F,
) -> Result<ValidToAddEvents<Timestamped<A>>, Error> {
Ok(ValidToAddEvents {
events: self
.events
.into_iter()
.map(move |timestamped| timestamped.map(&f))
.map(Timestamped::transpose)
.collect::<Result<Vec<_>, Error>>()?,
})
}
}