use std::collections::HashMap;
#[cfg(docsrs)]
pub use self::builder::Builder;
pub struct Map<T, Req>
where
T: target::Target<Req>,
{
map: HashMap<T::Key, T::Service>,
targeter: T,
}
impl Map<builder::StartHere, builder::StartHere> {
pub fn builder<Dst>() -> builder::Builder<Dst, builder::WantsKeyer, builder::WantsServiceMaker>
{
builder::Builder::new()
}
}
impl<T, Req> Map<T, Req>
where
T: target::Target<Req>,
{
fn new(targeter: T) -> Self {
Map {
map: HashMap::new(),
targeter,
}
}
}
impl<T, Req> Map<T, Req>
where
T: target::Target<Req>,
T::Key: Eq + std::hash::Hash,
{
pub fn service(&mut self, req: &Req) -> &mut T::Service {
let key = self.targeter.key(req);
self.map
.entry(key)
.or_insert_with(|| self.targeter.service(req))
}
pub fn retain<F>(&mut self, predicate: F)
where
F: FnMut(&T::Key, &mut T::Service) -> bool,
{
self.map.retain(predicate);
}
pub fn clear(&mut self) {
self.map.clear();
}
}
mod target {
pub trait Target<Dst> {
type Key;
type Service;
fn key(&self, dst: &Dst) -> Self::Key;
fn service(&self, dst: &Dst) -> Self::Service;
}
}
mod builder {
use std::marker::PhantomData;
pub struct Builder<Dst, K, S> {
_dst: PhantomData<fn(Dst)>,
keys: K,
svcs: S,
}
pub struct WantsKeyer;
pub struct WantsServiceMaker;
pub enum StartHere {}
pub struct Built<K, S> {
keys: K,
svcs: S,
}
impl<Dst> Builder<Dst, WantsKeyer, WantsServiceMaker> {
pub(super) fn new() -> Self {
Builder {
_dst: PhantomData,
keys: WantsKeyer,
svcs: WantsServiceMaker,
}
}
}
impl<Dst, S> Builder<Dst, WantsKeyer, S> {
pub fn keys<K, KK>(self, keyer: K) -> Builder<Dst, K, S>
where
K: Fn(&Dst) -> KK,
{
Builder {
_dst: PhantomData,
keys: keyer,
svcs: self.svcs,
}
}
}
impl<Dst, K> Builder<Dst, K, WantsServiceMaker> {
pub fn values<S, SS>(self, svcs: S) -> Builder<Dst, K, S>
where
S: Fn(&Dst) -> SS,
{
Builder {
_dst: PhantomData,
keys: self.keys,
svcs,
}
}
}
impl<Dst, K, S> Builder<Dst, K, S>
where
Built<K, S>: super::target::Target<Dst>,
<Built<K, S> as super::target::Target<Dst>>::Key: Eq + std::hash::Hash,
{
pub fn build(self) -> super::Map<Built<K, S>, Dst> {
super::Map::new(Built {
keys: self.keys,
svcs: self.svcs,
})
}
}
impl super::target::Target<StartHere> for StartHere {
type Key = StartHere;
type Service = StartHere;
fn key(&self, _: &StartHere) -> Self::Key {
match *self {}
}
fn service(&self, _: &StartHere) -> Self::Service {
match *self {}
}
}
impl<K, KK, S, SS, Dst> super::target::Target<Dst> for Built<K, S>
where
K: Fn(&Dst) -> KK,
S: Fn(&Dst) -> SS,
KK: Eq + std::hash::Hash,
{
type Key = KK;
type Service = SS;
fn key(&self, dst: &Dst) -> Self::Key {
(self.keys)(dst)
}
fn service(&self, dst: &Dst) -> Self::Service {
(self.svcs)(dst)
}
}
}
#[cfg(test)]
mod tests {
#[test]
fn smoke() {
let mut pool = super::Map::builder().keys(|_| "a").values(|_| "b").build();
pool.service(&"hello");
}
}