use std::{fmt::Display, hash::Hash, marker::PhantomData, sync::Arc};
use arc_swap::ArcSwap;
use super::{Outcome, Router};
use crate::envelope::Envelope;
pub struct MapRouter<C, S, P, R> {
config: PhantomData<C>,
state: S,
prepare: P,
route: R,
}
impl<C, R, K> MapRouter<C, (), (), R>
where
C: Send + Sync + 'static,
R: Fn(&Envelope) -> Outcome<K> + Send + Sync + 'static,
{
#[inline]
pub fn new(route: R) -> Self {
Self {
config: PhantomData,
state: (),
prepare: (),
route,
}
}
}
impl<C, R, K> Router<C> for MapRouter<C, (), (), R>
where
C: Send + Sync + 'static,
R: Fn(&Envelope) -> Outcome<K> + Send + Sync + 'static,
K: Clone + Hash + Eq + Display + Send + Sync,
{
type Key = K;
#[inline]
fn route(&self, envelope: &Envelope) -> Outcome<Self::Key> {
(self.route)(envelope)
}
}
impl<C, S, P, R, K> MapRouter<C, ArcSwap<S>, P, R>
where
C: Send + Sync + 'static,
S: Default + Send + Sync + 'static,
R: Fn(&Envelope, &S) -> Outcome<K> + Send + Sync + 'static,
P: Fn(&C, &S) -> S + Send + Sync + 'static,
{
#[inline]
pub fn with_state(prepare: P, route: R) -> Self {
Self {
config: PhantomData,
state: ArcSwap::default(),
prepare,
route,
}
}
}
impl<C, S, P, R, K> Router<C> for MapRouter<C, ArcSwap<S>, P, R>
where
C: Send + Sync + 'static,
S: Send + Sync + 'static,
R: Fn(&Envelope, &S) -> Outcome<K> + Send + Sync + 'static,
P: Fn(&C, &S) -> S + Send + Sync + 'static,
K: Clone + Hash + Eq + Display + Send + Sync,
{
type Key = K;
#[inline]
fn update(&self, config: &C) {
self.state
.rcu(|state| Arc::new((self.prepare)(config, state)));
}
#[inline]
fn route(&self, envelope: &Envelope) -> Outcome<Self::Key> {
let state = self.state.load();
(self.route)(envelope, &state)
}
}