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, $(($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 ::std::future::poll_fn(|cx| {
135 let mut ready = Pin::new(&mut fut1).poll(cx)?.is_ready();
136 $(ready = Pin::new(&mut $T).poll(cx)?.is_ready() && ready;)+
137
138 if ready {
139 Poll::Ready(Ok(()))
140 } else {
141 Poll::Pending
142 }
143 }).await
144 }
145
146 fn poll(&self, cx: &mut std::task::Context<'_>) -> Result<(), Self::Error> {
147 self.V1.poll(cx)?;
148 $(self.$T.poll(cx)?;)+
149 Ok(())
150 }
151
152 async fn shutdown(&self) {
153 self.V1.shutdown().await;
154 $(self.$T.shutdown().await;)+
155 }
156
157 async fn call(&self, req: $enum_type<V1R, $($R,)+>, ctx: ServiceCtx<'_, Self>) -> Result<Self::Response, Self::Error> {
158 match req {
159 $enum_type::V1(req) => ctx.call(&self.V1, req).await,
160 $($enum_type::$T(req) => ctx.call(&self.$T, req).await,)+
161 }
162 }
163 }
164
165 #[allow(non_snake_case)]
166 pub struct $fac_type<V1, V1C, $($T,)+ V1R, $($R,)+> {
167 V1: V1,
168 $($T: $T,)+
169 _t: PhantomData<(V1C, V1R, $($R,)+)>,
170 }
171
172 impl<V1: Clone, V1C, $($T: Clone,)+ V1R, $($R,)+> Clone for $fac_type<V1, V1C, $($T,)+ V1R, $($R,)+> {
173 fn clone(&self) -> Self {
174 Self {
175 _t: PhantomData,
176 V1: self.V1.clone(),
177 $($T: self.$T.clone(),)+
178 }
179 }
180 }
181
182 impl<V1: fmt::Debug, V1C, $($T: fmt::Debug,)+ V1R, $($R,)+> fmt::Debug for $fac_type<V1, V1C, $($T,)+ V1R, $($R,)+> {
183 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
184 f.debug_struct("Variant")
185 .field("V1", &self.V1)
186 $(.field(stringify!($T), &self.$T))+
187 .finish()
188 }
189 }
190
191 impl<V1, V1C, $($T,)+ V1R, $($R,)+> ServiceFactory<$enum_type<V1R, $($R),+>, V1C> for $fac_type<V1, V1C, $($T,)+ V1R, $($R,)+>
192 where
193 V1: ServiceFactory<V1R, V1C>,
194 V1C: Clone,
195 $($T: ServiceFactory< $R, V1C, Response = V1::Response, Error = V1::Error, InitError = V1::InitError>),+
196 {
197 type Response = V1::Response;
198 type Error = V1::Error;
199 type Service = $srv_type<V1::Service, $($T::Service,)+ V1R, $($R,)+>;
200 type InitError = V1::InitError;
201
202 async fn create(&self, cfg: V1C) -> Result<Self::Service, Self::InitError> {
203 Ok($srv_type {
204 V1: self.V1.create(cfg.clone()).await?,
205 $($T: self.$T.create(cfg.clone()).await?,)+
206 _t: PhantomData
207 })
208 }
209 }
210});
211
212#[rustfmt::skip]
213variant_impl!(v2, Variant2, VariantService2, VariantFactory2, (0, V2, V2R));
214#[rustfmt::skip]
215variant_impl!(v3, Variant3, VariantService3, VariantFactory3, (0, V2, V2R), (1, V3, V3R));
216#[rustfmt::skip]
217variant_impl!(v4, Variant4, VariantService4, VariantFactory4, (0, V2, V2R), (1, V3, V3R), (2, V4, V4R));
218#[rustfmt::skip]
219variant_impl!(v5, Variant5, VariantService5, VariantFactory5, (0, V2, V2R), (1, V3, V3R), (2, V4, V4R), (3, V5, V5R));
220#[rustfmt::skip]
221variant_impl!(v6, Variant6, VariantService6, VariantFactory6, (0, V2, V2R), (1, V3, V3R), (2, V4, V4R), (3, V5, V5R), (4, V6, V6R));
222#[rustfmt::skip]
223variant_impl!(v7, Variant7, VariantService7, VariantFactory7, (0, V2, V2R), (1, V3, V3R), (2, V4, V4R), (3, V5, V5R), (4, V6, V6R), (5, V7, V7R));
224#[rustfmt::skip]
225variant_impl!(v8, Variant8, VariantService8, VariantFactory8, (0, V2, V2R), (1, V3, V3R), (2, V4, V4R), (3, V5, V5R), (4, V6, V6R), (5, V7, V7R), (6, V8, V8R));
226
227#[rustfmt::skip]
228variant_impl_and!(VariantFactory2, VariantFactory3, V3, V3R, v3, (V2), (V2R));
229#[rustfmt::skip]
230variant_impl_and!(VariantFactory3, VariantFactory4, V4, V4R, v4, (V2, V3), (V2R, V3R));
231#[rustfmt::skip]
232variant_impl_and!(VariantFactory4, VariantFactory5, V5, V5R, v5, (V2, V3, V4), (V2R, V3R, V4R));
233#[rustfmt::skip]
234variant_impl_and!(VariantFactory5, VariantFactory6, V6, V6R, v6, (V2, V3, V4, V5), (V2R, V3R, V4R, V5R));
235#[rustfmt::skip]
236variant_impl_and!(VariantFactory6, VariantFactory7, V7, V7R, v7, (V2, V3, V4, V5, V6), (V2R, V3R, V4R, V5R, V6R));
237#[rustfmt::skip]
238variant_impl_and!(VariantFactory7, VariantFactory8, V8, V8R, v8, (V2, V3, V4, V5, V6, V7), (V2R, V3R, V4R, V5R, V6R, V7R));
239
240#[cfg(test)]
241mod tests {
242 use ntex_service::fn_factory;
243
244 use super::*;
245
246 #[derive(Debug, Clone)]
247 struct Srv1;
248
249 impl Service<()> for Srv1 {
250 type Response = usize;
251 type Error = ();
252
253 async fn ready(&self, _: ServiceCtx<'_, Self>) -> Result<(), Self::Error> {
254 Ok(())
255 }
256
257 async fn shutdown(&self) {}
258
259 async fn call(&self, _: (), _: ServiceCtx<'_, Self>) -> Result<usize, ()> {
260 Ok(1)
261 }
262 }
263
264 #[derive(Debug, Clone)]
265 struct Srv2;
266
267 impl Service<()> for Srv2 {
268 type Response = usize;
269 type Error = ();
270
271 async fn ready(&self, _: ServiceCtx<'_, Self>) -> Result<(), Self::Error> {
272 Ok(())
273 }
274
275 async fn shutdown(&self) {}
276
277 async fn call(&self, _: (), _: ServiceCtx<'_, Self>) -> Result<usize, ()> {
278 Ok(2)
279 }
280 }
281
282 #[ntex_macros::rt_test2]
283 async fn test_variant() {
284 let factory = variant(fn_factory(|| async { Ok::<_, ()>(Srv1) }));
285 assert!(format!("{factory:?}").contains("Variant"));
286
287 let factory = factory
288 .v2(fn_factory(|| async { Ok::<_, ()>(Srv2) }))
289 .clone()
290 .v3(fn_factory(|| async { Ok::<_, ()>(Srv2) }))
291 .clone();
292
293 let service = factory.pipeline(&()).await.unwrap().clone();
294 assert!(format!("{service:?}").contains("Variant"));
295
296 assert!(crate::future::lazy(|cx| service.poll(cx)).await.is_ok());
297 assert!(service.ready().await.is_ok());
298 service.shutdown().await;
299
300 assert_eq!(service.call(Variant3::V1(())).await, Ok(1));
301 assert_eq!(service.call(Variant3::V2(())).await, Ok(2));
302 assert_eq!(service.call(Variant3::V3(())).await, Ok(2));
303 }
304}