1#![allow(non_snake_case)]
3use std::{fmt, marker::PhantomData, task::Poll};
4
5use ntex_service::{IntoServiceFactory, Service, ServiceCtx, ServiceFactory};
6
7pub fn variant<V1: ServiceFactory<V1R, V1C>, V1R, V1C>(
11 factory: V1,
12) -> Variant<V1, V1R, V1C> {
13 Variant {
14 factory,
15 _t: PhantomData,
16 }
17}
18
19pub struct Variant<A, AR, AC> {
21 factory: A,
22 _t: PhantomData<(AR, AC)>,
23}
24
25impl<A, AR, AC> Variant<A, AR, AC>
26where
27 A: ServiceFactory<AR, AC>,
28 AC: Clone,
29{
30 pub fn v2<B, BR, F>(self, factory: F) -> VariantFactory2<A, AC, B, AR, BR>
32 where
33 B: ServiceFactory<
34 BR,
35 AC,
36 Response = A::Response,
37 Error = A::Error,
38 InitError = A::InitError,
39 >,
40 F: IntoServiceFactory<B, BR, AC>,
41 {
42 VariantFactory2 {
43 V1: self.factory,
44 V2: factory.into_factory(),
45 _t: PhantomData,
46 }
47 }
48}
49
50impl<A, AR, AC> fmt::Debug for Variant<A, AR, AC>
51where
52 A: fmt::Debug,
53{
54 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55 f.debug_struct("Variant")
56 .field("V1", &self.factory)
57 .finish()
58 }
59}
60
61macro_rules! variant_impl_and ({$fac1_type:ident, $fac2_type:ident, $name:ident, $r_name:ident, $m_name:ident, ($($T:ident),+), ($($R:ident),+)} => {
62
63 #[allow(non_snake_case)]
64 impl<V1, V1C, $($T,)+ V1R, $($R,)+> $fac1_type<V1, V1C, $($T,)+ V1R, $($R,)+>
65 where
66 V1: ServiceFactory<V1R, V1C>,
67 {
68 pub fn $m_name<$name, $r_name, F>(self, factory: F) -> $fac2_type<V1, V1C, $($T,)+ $name, V1R, $($R,)+ $r_name>
70 where $name: ServiceFactory<$r_name, V1C,
71 Response = V1::Response,
72 Error = V1::Error,
73 InitError = V1::InitError>,
74 F: IntoServiceFactory<$name, $r_name, V1C>,
75 {
76 $fac2_type {
77 V1: self.V1,
78 $($T: self.$T,)+
79 $name: factory.into_factory(),
80 _t: PhantomData
81 }
82 }
83 }
84});
85
86macro_rules! variant_impl ({$mod_name:ident, $enum_type:ident, $srv_type:ident, $fac_type:ident, $num:literal, $(($n:tt, $T:ident, $R:ident)),+} => {
87
88 #[allow(non_snake_case, missing_debug_implementations)]
89 pub enum $enum_type<V1R, $($R),+> {
90 V1(V1R),
91 $($T($R),)+
92 }
93
94 #[allow(non_snake_case)]
95 pub struct $srv_type<V1, $($T,)+ V1R, $($R,)+> {
96 V1: V1,
97 $($T: $T,)+
98 _t: PhantomData<(V1R, $($R),+)>,
99 }
100
101 impl<V1: Clone, $($T: Clone,)+ V1R, $($R,)+> Clone for $srv_type<V1, $($T,)+ V1R, $($R,)+> {
102 fn clone(&self) -> Self {
103 Self {
104 _t: PhantomData,
105 V1: self.V1.clone(),
106 $($T: self.$T.clone(),)+
107 }
108 }
109 }
110
111 impl<V1: fmt::Debug, $($T: fmt::Debug,)+ V1R, $($R,)+> fmt::Debug for $srv_type<V1, $($T,)+ V1R, $($R,)+> {
112 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113 f.debug_struct(stringify!($srv_type))
114 .field("V1", &self.V1)
115 $(.field(stringify!($T), &self.$T))+
116 .finish()
117 }
118 }
119
120 impl<V1, $($T,)+ V1R, $($R,)+> Service<$enum_type<V1R, $($R,)+>> for $srv_type<V1, $($T,)+ V1R, $($R,)+>
121 where
122 V1: Service<V1R>,
123 $($T: Service<$R, Response = V1::Response, Error = V1::Error>),+
124 {
125 type Response = V1::Response;
126 type Error = V1::Error;
127
128 async fn ready(&self, ctx: ServiceCtx<'_, Self>) -> Result<(), Self::Error> {
129 use std::{future::Future, pin::Pin};
130
131 let mut fut1 = ::std::pin::pin!(ctx.ready(&self.V1));
132 $(let mut $T = ::std::pin::pin!(ctx.ready(&self.$T));)+
133
134 let mut ready: [bool; $num] = [false; $num];
135
136 ::std::future::poll_fn(|cx| {
137 if !ready[$num-1] {
138 ready[$num-1] = Pin::new(&mut fut1).poll(cx)?.is_ready();
139 }
140 $(if !ready[$n] {
141 ready[$n] = Pin::new(&mut $T).poll(cx)?.is_ready();
142 })+;
143
144 for v in &ready[..] {
145 if !v {
146 return Poll::Pending
147 }
148 }
149 Poll::Ready(Ok(()))
150 }).await
151 }
152
153 fn poll(&self, cx: &mut std::task::Context<'_>) -> Result<(), Self::Error> {
154 self.V1.poll(cx)?;
155 $(self.$T.poll(cx)?;)+
156 Ok(())
157 }
158
159 async fn shutdown(&self) {
160 self.V1.shutdown().await;
161 $(self.$T.shutdown().await;)+
162 }
163
164 async fn call(&self, req: $enum_type<V1R, $($R,)+>, ctx: ServiceCtx<'_, Self>) -> Result<Self::Response, Self::Error> {
165 match req {
166 $enum_type::V1(req) => ctx.call(&self.V1, req).await,
167 $($enum_type::$T(req) => ctx.call(&self.$T, req).await,)+
168 }
169 }
170 }
171
172 #[allow(non_snake_case)]
173 pub struct $fac_type<V1, V1C, $($T,)+ V1R, $($R,)+> {
174 V1: V1,
175 $($T: $T,)+
176 _t: PhantomData<(V1C, V1R, $($R,)+)>,
177 }
178
179 impl<V1: Clone, V1C, $($T: Clone,)+ V1R, $($R,)+> Clone for $fac_type<V1, V1C, $($T,)+ V1R, $($R,)+> {
180 fn clone(&self) -> Self {
181 Self {
182 _t: PhantomData,
183 V1: self.V1.clone(),
184 $($T: self.$T.clone(),)+
185 }
186 }
187 }
188
189 impl<V1: fmt::Debug, V1C, $($T: fmt::Debug,)+ V1R, $($R,)+> fmt::Debug for $fac_type<V1, V1C, $($T,)+ V1R, $($R,)+> {
190 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
191 f.debug_struct("Variant")
192 .field("V1", &self.V1)
193 $(.field(stringify!($T), &self.$T))+
194 .finish()
195 }
196 }
197
198 impl<V1, V1C, $($T,)+ V1R, $($R,)+> ServiceFactory<$enum_type<V1R, $($R),+>, V1C> for $fac_type<V1, V1C, $($T,)+ V1R, $($R,)+>
199 where
200 V1: ServiceFactory<V1R, V1C>,
201 V1C: Clone,
202 $($T: ServiceFactory< $R, V1C, Response = V1::Response, Error = V1::Error, InitError = V1::InitError>),+
203 {
204 type Response = V1::Response;
205 type Error = V1::Error;
206 type Service = $srv_type<V1::Service, $($T::Service,)+ V1R, $($R,)+>;
207 type InitError = V1::InitError;
208
209 async fn create(&self, cfg: V1C) -> Result<Self::Service, Self::InitError> {
210 Ok($srv_type {
211 V1: self.V1.create(cfg.clone()).await?,
212 $($T: self.$T.create(cfg.clone()).await?,)+
213 _t: PhantomData
214 })
215 }
216 }
217});
218
219#[rustfmt::skip]
220variant_impl!(v2, Variant2, VariantService2, VariantFactory2, 2, (0, V2, V2R));
221#[rustfmt::skip]
222variant_impl!(v3, Variant3, VariantService3, VariantFactory3, 3, (0, V2, V2R), (1, V3, V3R));
223#[rustfmt::skip]
224variant_impl!(v4, Variant4, VariantService4, VariantFactory4, 4, (0, V2, V2R), (1, V3, V3R), (2, V4, V4R));
225#[rustfmt::skip]
226variant_impl!(v5, Variant5, VariantService5, VariantFactory5, 5, (0, V2, V2R), (1, V3, V3R), (2, V4, V4R), (3, V5, V5R));
227#[rustfmt::skip]
228variant_impl!(v6, Variant6, VariantService6, VariantFactory6, 6, (0, V2, V2R), (1, V3, V3R), (2, V4, V4R), (3, V5, V5R), (4, V6, V6R));
229#[rustfmt::skip]
230variant_impl!(v7, Variant7, VariantService7, VariantFactory7, 7, (0, V2, V2R), (1, V3, V3R), (2, V4, V4R), (3, V5, V5R), (4, V6, V6R), (5, V7, V7R));
231#[rustfmt::skip]
232variant_impl!(v8, Variant8, VariantService8, VariantFactory8, 8, (0, V2, V2R), (1, V3, V3R), (2, V4, V4R), (3, V5, V5R), (4, V6, V6R), (5, V7, V7R), (6, V8, V8R));
233
234#[rustfmt::skip]
235variant_impl_and!(VariantFactory2, VariantFactory3, V3, V3R, v3, (V2), (V2R));
236#[rustfmt::skip]
237variant_impl_and!(VariantFactory3, VariantFactory4, V4, V4R, v4, (V2, V3), (V2R, V3R));
238#[rustfmt::skip]
239variant_impl_and!(VariantFactory4, VariantFactory5, V5, V5R, v5, (V2, V3, V4), (V2R, V3R, V4R));
240#[rustfmt::skip]
241variant_impl_and!(VariantFactory5, VariantFactory6, V6, V6R, v6, (V2, V3, V4, V5), (V2R, V3R, V4R, V5R));
242#[rustfmt::skip]
243variant_impl_and!(VariantFactory6, VariantFactory7, V7, V7R, v7, (V2, V3, V4, V5, V6), (V2R, V3R, V4R, V5R, V6R));
244#[rustfmt::skip]
245variant_impl_and!(VariantFactory7, VariantFactory8, V8, V8R, v8, (V2, V3, V4, V5, V6, V7), (V2R, V3R, V4R, V5R, V6R, V7R));
246
247#[cfg(test)]
248mod tests {
249 use ntex_service::{fn_factory, fn_service};
250
251 use super::*;
252 use crate::time;
253
254 #[derive(Debug, Clone)]
255 struct Srv1;
256
257 impl Service<()> for Srv1 {
258 type Response = usize;
259 type Error = ();
260
261 async fn ready(&self, _: ServiceCtx<'_, Self>) -> Result<(), Self::Error> {
262 Ok(())
263 }
264
265 async fn shutdown(&self) {}
266
267 async fn call(&self, _: (), _: ServiceCtx<'_, Self>) -> Result<usize, ()> {
268 Ok(1)
269 }
270 }
271
272 #[derive(Debug, Clone)]
273 struct Srv2;
274
275 impl Service<()> for Srv2 {
276 type Response = usize;
277 type Error = ();
278
279 async fn ready(&self, _: ServiceCtx<'_, Self>) -> Result<(), Self::Error> {
280 Ok(())
281 }
282
283 async fn shutdown(&self) {}
284
285 async fn call(&self, _: (), _: ServiceCtx<'_, Self>) -> Result<usize, ()> {
286 Ok(2)
287 }
288 }
289
290 #[ntex_macros::rt_test2]
291 async fn test_variant() {
292 let factory = variant(fn_factory(|| async { Ok::<_, ()>(Srv1) }));
293 assert!(format!("{factory:?}").contains("Variant"));
294
295 let factory = factory
296 .v2(fn_factory(|| async { Ok::<_, ()>(Srv2) }))
297 .clone()
298 .v3(fn_factory(|| async { Ok::<_, ()>(Srv2) }))
299 .clone();
300
301 let service = factory.pipeline(&()).await.unwrap().clone();
302 assert!(format!("{service:?}").contains("Variant"));
303
304 assert!(crate::future::lazy(|cx| service.poll(cx)).await.is_ok());
305 assert!(service.ready().await.is_ok());
306 service.shutdown().await;
307
308 assert_eq!(service.call(Variant3::V1(())).await, Ok(1));
309 assert_eq!(service.call(Variant3::V2(())).await, Ok(2));
310 assert_eq!(service.call(Variant3::V3(())).await, Ok(2));
311 }
312
313 #[ntex_macros::rt_test2]
314 async fn test_variant_readiness() {
315 #[derive(Debug, Clone)]
316 struct Srv5;
317
318 impl Service<()> for Srv5 {
319 type Response = usize;
320 type Error = ();
321 async fn ready(&self, _: ServiceCtx<'_, Self>) -> Result<(), Self::Error> {
322 time::sleep(time::Millis(50)).await;
323 time::sleep(time::Millis(50)).await;
324 time::sleep(time::Millis(50)).await;
325 time::sleep(time::Millis(50)).await;
326 Ok(())
327 }
328 async fn shutdown(&self) {}
329 async fn call(&self, _: (), _: ServiceCtx<'_, Self>) -> Result<usize, ()> {
330 Ok(2)
331 }
332 }
333
334 let factory = variant(fn_service(|()| async { Ok::<_, ()>(0) }))
335 .v2(fn_factory(|| async { Ok::<_, ()>(Srv5) }))
336 .v3(fn_service(|()| crate::future::Ready::Ok::<_, ()>(2)));
337 let service = factory.pipeline(&()).await.unwrap().clone();
338 assert!(service.ready().await.is_ok());
339 }
340}