use std::any::{Any, TypeId};
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
pub trait Aggregator: Send + Sync + 'static {
type Input: Send + 'static;
type State: Send + Default + 'static;
type Output: Send + 'static;
fn fold(state: &mut Self::State, input: Self::Input);
fn merge(left: &mut Self::State, right: Self::State);
fn finalize(state: Self::State) -> Self::Output;
}
pub(crate) struct Holder<A: Aggregator> {
shards: Vec<Mutex<A::State>>,
}
impl<A: Aggregator> Holder<A> {
fn new(shards: usize) -> Self {
Holder {
shards: (0..shards.max(1))
.map(|_| Mutex::new(A::State::default()))
.collect(),
}
}
fn fold(&self, shard: usize, input: A::Input) {
let idx = shard % self.shards.len();
let mut guard = self.shards[idx].lock().unwrap();
A::fold(&mut guard, input);
}
}
pub(crate) trait AnyAggregator: Send + Sync {
fn as_any(&self) -> &dyn Any;
fn finalize_erased(&self) -> Box<dyn Any + Send>;
}
impl<A: Aggregator> AnyAggregator for Holder<A> {
fn as_any(&self) -> &dyn Any {
self
}
fn finalize_erased(&self) -> Box<dyn Any + Send> {
let mut acc = A::State::default();
for shard in &self.shards {
let mut guard = shard.lock().unwrap();
A::merge(&mut acc, std::mem::take(&mut guard));
}
Box::new(A::finalize(acc))
}
}
#[derive(Default)]
pub(crate) struct Aggregators {
map: HashMap<TypeId, Arc<dyn AnyAggregator>>,
}
impl Aggregators {
pub fn insert<A: Aggregator>(&mut self, shards: usize) {
self.map
.insert(TypeId::of::<A>(), Arc::new(Holder::<A>::new(shards)));
}
pub fn fold<A: Aggregator>(&self, shard: usize, input: A::Input) {
match self.map.get(&TypeId::of::<A>()) {
Some(h) => h
.as_any()
.downcast_ref::<Holder<A>>()
.expect("aggregator type mismatch")
.fold(shard, input),
None => panic!("aggregator {} not registered", std::any::type_name::<A>()),
}
}
pub fn finalize_all(&self) -> HashMap<TypeId, Box<dyn Any + Send>> {
self.map
.iter()
.map(|(k, v)| (*k, v.finalize_erased()))
.collect()
}
}