xitca_service/service/
ext.rs1use crate::{
2 middleware::{AsyncFn, EnclosedBuilder, EnclosedFnBuilder, Map, MapBuilder, MapErr, MapErrorBuilder},
3 pipeline::{PipelineT, marker},
4};
5
6use super::Service;
7
8pub trait ServiceExt<Arg>: Service<Arg> {
10 fn enclosed<T>(self, build: T) -> EnclosedBuilder<Self, T>
13 where
14 T: Service<Result<Self::Response, Self::Error>>,
15 Self: Sized,
16 {
17 PipelineT::new(self, build)
18 }
19
20 fn enclosed_fn<T, Req, O>(self, func: T) -> EnclosedFnBuilder<Self, T>
22 where
23 T: core::ops::AsyncFn(&Self::Response, Req) -> O + Clone,
24 Self: Sized,
25 {
26 self.enclosed(AsyncFn(func))
27 }
28
29 fn map<F, Res, ResMap>(self, mapper: F) -> MapBuilder<Self, F>
32 where
33 F: Fn(Res) -> ResMap + Clone,
34 Self: Sized,
35 {
36 self.enclosed(Map(mapper))
37 }
38
39 fn map_err<F, Err, ErrMap>(self, err: F) -> MapErrorBuilder<Self, F>
41 where
42 F: Fn(Err) -> ErrMap + Clone,
43 Self: Sized,
44 {
45 self.enclosed(MapErr(err))
46 }
47
48 fn and_then<F>(self, factory: F) -> PipelineT<Self, F, marker::BuildAndThen>
51 where
52 F: Service<Arg>,
53 Self: Sized,
54 {
55 PipelineT::new(self, factory)
56 }
57}
58
59impl<S, Arg> ServiceExt<Arg> for S where S: Service<Arg> {}
60
61#[cfg(test)]
62mod test {
63 use xitca_unsafe_collection::futures::NowOrPanic;
64
65 use crate::fn_service;
66
67 use super::*;
68
69 #[derive(Clone)]
70 struct DummyMiddleware;
71
72 struct DummyMiddlewareService<S>(S);
73
74 impl<S, E> Service<Result<S, E>> for DummyMiddleware {
75 type Response = DummyMiddlewareService<S>;
76 type Error = E;
77
78 async fn call(&self, res: Result<S, E>) -> Result<Self::Response, Self::Error> {
79 res.map(DummyMiddlewareService)
80 }
81 }
82
83 impl<S, Req> Service<Req> for DummyMiddlewareService<S>
84 where
85 S: Service<Req>,
86 {
87 type Response = S::Response;
88 type Error = S::Error;
89
90 async fn call(&self, req: Req) -> Result<Self::Response, Self::Error> {
91 self.0.call(req).await
92 }
93 }
94
95 async fn index(s: &'static str) -> Result<&'static str, ()> {
96 Ok(s)
97 }
98
99 #[cfg(feature = "alloc")]
100 #[test]
101 fn service_object() {
102 let service = fn_service(index)
103 .enclosed(DummyMiddleware)
104 .call(())
105 .now_or_panic()
106 .unwrap();
107
108 let res = service.call("996").now_or_panic().unwrap();
109 assert_eq!(res, "996");
110 }
111
112 #[test]
113 fn map() {
114 let service = fn_service(index).map(|_| "251").call(()).now_or_panic().unwrap();
115
116 let err = service.call("996").now_or_panic().ok().unwrap();
117 assert_eq!(err, "251");
118 }
119
120 #[test]
121 fn map_err() {
122 let service = fn_service(|_: &str| async { Err::<(), _>(()) })
123 .map_err(|_| "251")
124 .call(())
125 .now_or_panic()
126 .unwrap();
127
128 let err = service.call("996").now_or_panic().err().unwrap();
129 assert_eq!(err, "251");
130 }
131
132 #[test]
133 fn enclosed_fn() {
134 async fn enclosed<S>(service: &S, req: &'static str) -> Result<&'static str, ()>
135 where
136 S: Service<&'static str, Response = &'static str, Error = ()>,
137 {
138 let res = service.call(req).await?;
139 assert_eq!(res, "996");
140 Ok("251")
141 }
142
143 let res = fn_service(index)
144 .enclosed_fn(enclosed)
145 .enclosed_fn(async |service, req| service.call(req).await)
146 .call(())
147 .now_or_panic()
148 .unwrap()
149 .call("996")
150 .now_or_panic()
151 .ok()
152 .unwrap();
153
154 assert_eq!(res, "251");
155 }
156
157 #[cfg(feature = "alloc")]
158 #[test]
159 fn enclosed_opt() {
160 let service = fn_service(index)
161 .enclosed(Some(DummyMiddleware))
162 .call(())
163 .now_or_panic()
164 .unwrap();
165
166 let res = service.call("996").now_or_panic().unwrap();
167 assert_eq!(res, "996");
168
169 let service = fn_service(index)
170 .enclosed(Option::<DummyMiddleware>::None)
171 .call(())
172 .now_or_panic()
173 .unwrap();
174
175 let res = service.call("996").now_or_panic().unwrap();
176 assert_eq!(res, "996");
177 }
178}