1use std::{fmt::Display, hash::Hash, marker::PhantomData, sync::Arc};
2
3use arc_swap::ArcSwap;
4
5use super::{Outcome, Router};
6use crate::envelope::Envelope;
7
8pub struct MapRouter<C, S, P, R> {
9 config: PhantomData<C>,
10 state: S,
11 prepare: P,
12 route: R,
13}
14
15impl<C, R, K> MapRouter<C, (), (), R>
17where
18 C: Send + Sync + 'static,
19 R: Fn(&Envelope) -> Outcome<K> + Send + Sync + 'static,
20{
21 #[inline]
22 pub fn new(route: R) -> Self {
23 Self {
24 config: PhantomData,
25 state: (),
26 prepare: (),
27 route,
28 }
29 }
30}
31
32impl<C, R, K> Router<C> for MapRouter<C, (), (), R>
33where
34 C: Send + Sync + 'static,
35 R: Fn(&Envelope) -> Outcome<K> + Send + Sync + 'static,
36 K: Clone + Hash + Eq + Display + Send + Sync,
37{
38 type Key = K;
39
40 #[inline]
41 fn route(&self, envelope: &Envelope) -> Outcome<Self::Key> {
42 (self.route)(envelope)
43 }
44}
45
46impl<C, S, P, R, K> MapRouter<C, ArcSwap<S>, P, R>
48where
49 C: Send + Sync + 'static,
50 S: Default + Send + Sync + 'static,
51 R: Fn(&Envelope, &S) -> Outcome<K> + Send + Sync + 'static,
52 P: Fn(&C, &S) -> S + Send + Sync + 'static,
53{
54 #[inline]
55 pub fn with_state(prepare: P, route: R) -> Self {
56 Self {
57 config: PhantomData,
58 state: ArcSwap::default(),
59 prepare,
60 route,
61 }
62 }
63}
64
65impl<C, S, P, R, K> Router<C> for MapRouter<C, ArcSwap<S>, P, R>
66where
67 C: Send + Sync + 'static,
68 S: Send + Sync + 'static,
69 R: Fn(&Envelope, &S) -> Outcome<K> + Send + Sync + 'static,
70 P: Fn(&C, &S) -> S + Send + Sync + 'static,
71 K: Clone + Hash + Eq + Display + Send + Sync,
72{
73 type Key = K;
74
75 #[inline]
76 fn update(&self, config: &C) {
77 self.state
78 .rcu(|state| Arc::new((self.prepare)(config, state)));
79 }
80
81 #[inline]
82 fn route(&self, envelope: &Envelope) -> Outcome<Self::Key> {
83 let state = self.state.load();
84 (self.route)(envelope, &state)
85 }
86}