hyper_util/client/pool/
map.rs1use std::collections::HashMap;
32
33#[cfg(docsrs)]
35pub use self::builder::Builder;
36
37pub struct Map<T, Req>
41where
42 T: target::Target<Req>,
43{
44 map: HashMap<T::Key, T::Service>,
45 targeter: T,
46}
47
48impl Map<builder::StartHere, builder::StartHere> {
51 #[allow(
52 rustdoc::broken_intra_doc_links,
53 reason = "this link is intended for docs.rs builds"
54 )]
55 pub fn builder<Dst>() -> builder::Builder<Dst, builder::WantsKeyer, builder::WantsServiceMaker>
57 {
58 builder::Builder::new()
59 }
60}
61
62impl<T, Req> Map<T, Req>
63where
64 T: target::Target<Req>,
65{
66 fn new(targeter: T) -> Self {
67 Map {
68 map: HashMap::new(),
69 targeter,
70 }
71 }
72}
73
74impl<T, Req> Map<T, Req>
75where
76 T: target::Target<Req>,
77 T::Key: Eq + std::hash::Hash,
78{
79 pub fn service(&mut self, req: &Req) -> &mut T::Service {
81 let key = self.targeter.key(req);
82 self.map
83 .entry(key)
84 .or_insert_with(|| self.targeter.service(req))
85 }
86
87 pub fn retain<F>(&mut self, predicate: F)
89 where
90 F: FnMut(&T::Key, &mut T::Service) -> bool,
91 {
92 self.map.retain(predicate);
93 }
94
95 pub fn clear(&mut self) {
97 self.map.clear();
98 }
99}
100
101mod target {
103 pub trait Target<Dst> {
104 type Key;
105 type Service;
106
107 fn key(&self, dst: &Dst) -> Self::Key;
108 fn service(&self, dst: &Dst) -> Self::Service;
109 }
110}
111
112mod builder {
114 use std::marker::PhantomData;
115
116 pub struct Builder<Dst, K, S> {
124 _dst: PhantomData<fn(Dst)>,
125 keys: K,
126 svcs: S,
127 }
128
129 pub struct WantsKeyer;
130 pub struct WantsServiceMaker;
131
132 pub enum StartHere {}
133
134 pub struct Built<K, S> {
135 keys: K,
136 svcs: S,
137 }
138
139 impl<Dst> Builder<Dst, WantsKeyer, WantsServiceMaker> {
140 pub(super) fn new() -> Self {
141 Builder {
142 _dst: PhantomData,
143 keys: WantsKeyer,
144 svcs: WantsServiceMaker,
145 }
146 }
147 }
148
149 impl<Dst, S> Builder<Dst, WantsKeyer, S> {
150 pub fn keys<K, KK>(self, keyer: K) -> Builder<Dst, K, S>
152 where
153 K: Fn(&Dst) -> KK,
154 {
155 Builder {
156 _dst: PhantomData,
157 keys: keyer,
158 svcs: self.svcs,
159 }
160 }
161 }
162
163 impl<Dst, K> Builder<Dst, K, WantsServiceMaker> {
164 pub fn values<S, SS>(self, svcs: S) -> Builder<Dst, K, S>
166 where
167 S: Fn(&Dst) -> SS,
168 {
169 Builder {
170 _dst: PhantomData,
171 keys: self.keys,
172 svcs,
173 }
174 }
175 }
176
177 impl<Dst, K, S> Builder<Dst, K, S>
178 where
179 Built<K, S>: super::target::Target<Dst>,
180 <Built<K, S> as super::target::Target<Dst>>::Key: Eq + std::hash::Hash,
181 {
182 pub fn build(self) -> super::Map<Built<K, S>, Dst> {
184 super::Map::new(Built {
185 keys: self.keys,
186 svcs: self.svcs,
187 })
188 }
189 }
190
191 impl super::target::Target<StartHere> for StartHere {
192 type Key = StartHere;
193 type Service = StartHere;
194
195 fn key(&self, _: &StartHere) -> Self::Key {
196 match *self {}
197 }
198
199 fn service(&self, _: &StartHere) -> Self::Service {
200 match *self {}
201 }
202 }
203
204 impl<K, KK, S, SS, Dst> super::target::Target<Dst> for Built<K, S>
205 where
206 K: Fn(&Dst) -> KK,
207 S: Fn(&Dst) -> SS,
208 KK: Eq + std::hash::Hash,
209 {
210 type Key = KK;
211 type Service = SS;
212
213 fn key(&self, dst: &Dst) -> Self::Key {
214 (self.keys)(dst)
215 }
216
217 fn service(&self, dst: &Dst) -> Self::Service {
218 (self.svcs)(dst)
219 }
220 }
221}
222
223#[cfg(test)]
224mod tests {
225 #[test]
226 fn smoke() {
227 let mut pool = super::Map::builder().keys(|_| "a").values(|_| "b").build();
228 pool.service(&"hello");
229 }
230}