1use std::{fmt, future, pin::Pin, task::Context, task::Poll};
2
3use crate::pl_inner::PipelineApi;
4use crate::{IntoService, Service, util::BoxFuture};
5
6pub use crate::pl_factory::{PipelineFactory, PipelineStateFactory};
7pub use crate::pl_state::{PipelineState, PipelineStateBinding};
8
9pub struct Pipeline<Req, Res, Err> {
13 api: PipelineApi<Req, Res, Err>,
14}
15
16pub struct PipelineBinding<Req, Res, Err> {
18 idx: u32,
19 api: PipelineApi<Req, Res, Err>,
20}
21
22impl<Req, Res, Err> Pipeline<Req, Res, Err>
23where
24 Req: 'static,
25 Res: 'static,
26 Err: 'static,
27{
28 #[inline]
29 pub fn new<S, St>(f: impl IntoService<S, St, Req>) -> Self
31 where
32 S: Service<St, Req, Res = Res, Error = Err> + 'static,
33 St: Default + 'static,
34 {
35 Pipeline {
36 api: PipelineApi::new(f.into_service(), St::default()),
37 }
38 }
39
40 #[inline]
41 pub fn with<S, St>(st: St, f: impl IntoService<S, St, Req>) -> Self
43 where
44 S: Service<St, Req, Res = Res, Error = Err> + 'static,
45 St: 'static,
46 {
47 Pipeline {
48 api: PipelineApi::new(f.into_service(), st),
49 }
50 }
51
52 #[inline]
53 pub async fn ready(&self) -> Result<(), Err> {
55 future::poll_fn(|cx| self.api.poll_ready(cx)).await
56 }
57
58 #[inline]
59 pub async fn call(&self, req: Req) -> Result<Res, Err> {
62 let pl = self.bind();
63 pl.api.call(pl.idx, req, true).await
64 }
65
66 #[inline]
67 pub fn call_static(&self, req: Req) -> PipelineCall<Req, Res, Err> {
72 PipelineCall::new(self.bind(), req, true)
73 }
74
75 #[inline]
76 pub fn call_nowait(&self, req: Req) -> PipelineCall<Req, Res, Err> {
81 PipelineCall::new(self.bind(), req, false)
82 }
83
84 #[inline]
85 pub fn poll_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), Err>> {
87 self.api.poll_ready(cx)
88 }
89
90 #[inline]
91 pub fn poll_shutdown(&self, cx: &mut Context<'_>) -> Poll<()> {
93 self.api.poll_shutdown(cx)
94 }
95
96 #[inline]
97 pub fn is_shutdown(&self) -> bool {
99 self.api.is_shutdown()
100 }
101
102 #[inline]
103 pub async fn shutdown(&self) {
105 future::poll_fn(|cx| self.api.poll_shutdown(cx)).await;
106 }
107
108 #[inline]
109 pub fn bind(&self) -> PipelineBinding<Req, Res, Err> {
113 PipelineBinding::new(self)
114 }
115}
116
117impl<Req, Res, Err> Drop for Pipeline<Req, Res, Err> {
118 #[inline]
119 fn drop(&mut self) {
120 self.api.unreg(0);
121 }
122}
123
124impl<Req, Res, Err> PipelineBinding<Req, Res, Err>
125where
126 Req: 'static,
127 Res: 'static,
128 Err: 'static,
129{
130 fn new(pl: &Pipeline<Req, Res, Err>) -> Self {
131 Self {
132 idx: pl.api.reg(),
133 api: pl.api.clone(),
134 }
135 }
136
137 pub(crate) fn with(idx: u32, api: PipelineApi<Req, Res, Err>) -> Self {
138 Self { idx, api }
139 }
140
141 #[inline]
142 pub async fn ready(&self) -> Result<(), Err> {
144 self.api.ready(self.idx).await
145 }
146
147 #[inline]
148 pub async fn call(&self, req: Req) -> Result<Res, Err> {
151 let pl = self.clone();
152 pl.api.call(pl.idx, req, true).await
153 }
154
155 #[inline]
156 pub fn call_static(&self, req: Req) -> PipelineCall<Req, Res, Err> {
161 PipelineCall::new(self.clone(), req, true)
162 }
163
164 #[inline]
165 pub fn call_nowait(&self, req: Req) -> PipelineCall<Req, Res, Err> {
170 PipelineCall::new(self.clone(), req, false)
171 }
172}
173
174impl<Req, Res, Err> Drop for PipelineBinding<Req, Res, Err> {
175 #[inline]
176 fn drop(&mut self) {
177 self.api.unreg(self.idx);
178 }
179}
180
181impl<Req, Res, Err> Clone for PipelineBinding<Req, Res, Err> {
182 fn clone(&self) -> Self {
183 Self {
184 idx: self.api.reg(),
185 api: self.api.clone(),
186 }
187 }
188}
189
190#[must_use = "futures do nothing unless polled"]
191pub struct PipelineCall<Req, Res, Err> {
193 #[allow(dead_code)]
194 pl: PipelineBinding<Req, Res, Err>,
195 fut: BoxFuture<'static, Result<Res, Err>>,
196}
197
198impl<Req, Res, Err> PipelineCall<Req, Res, Err> {
199 #[allow(clippy::missing_transmute_annotations)]
200 fn new(pl: PipelineBinding<Req, Res, Err>, req: Req, ready: bool) -> Self {
201 PipelineCall {
204 fut: unsafe { std::mem::transmute(pl.api.call(pl.idx, req, ready)) },
205 pl,
206 }
207 }
208}
209
210impl<Req, Res, Err> future::Future for PipelineCall<Req, Res, Err> {
211 type Output = Result<Res, Err>;
212
213 #[inline]
214 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
215 Pin::new(&mut self.as_mut().fut).poll(cx)
216 }
217}
218
219impl<Req, Res, Err> fmt::Debug for Pipeline<Req, Res, Err> {
220 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
221 f.debug_struct("Pipeline").finish()
222 }
223}
224
225impl<Req, Res, Err> fmt::Debug for PipelineBinding<Req, Res, Err> {
226 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
227 f.debug_struct("PipelineBinding")
228 .field("idx", &self.idx)
229 .finish()
230 }
231}
232
233impl<Req, Res, Err> fmt::Debug for PipelineCall<Req, Res, Err> {
234 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
235 f.debug_struct("PipelineCall").finish()
236 }
237}