tower/util/
optional_layer.rs1use crate::BoxError;
8use pin_project_lite::pin_project;
9use std::{
10 future::Future,
11 pin::Pin,
12 task::{Context, Poll},
13};
14use tower_layer::Layer;
15use tower_service::Service;
16
17#[derive(Clone, Copy, Debug)]
33pub struct OptionLayer<L> {
34 layer: Option<L>,
35}
36
37impl<L> OptionLayer<L> {
38 pub const fn new(layer: Option<L>) -> Self {
40 OptionLayer { layer }
41 }
42}
43
44impl<L> From<Option<L>> for OptionLayer<L> {
45 fn from(layer: Option<L>) -> Self {
46 OptionLayer::new(layer)
47 }
48}
49
50impl<S, L> Layer<S> for OptionLayer<L>
51where
52 L: Layer<S>,
53{
54 type Service = OptionService<L::Service, S>;
55
56 fn layer(&self, inner: S) -> Self::Service {
57 match &self.layer {
58 Some(layer) => OptionService::Some(layer.layer(inner)),
59 None => OptionService::None(inner),
60 }
61 }
62}
63
64#[derive(Clone, Copy, Debug)]
71pub enum OptionService<A, B> {
72 Some(A),
74 None(B),
76}
77
78impl<A, B, Request> Service<Request> for OptionService<A, B>
79where
80 A: Service<Request>,
81 A::Error: Into<BoxError>,
82 B: Service<Request, Response = A::Response>,
83 B::Error: Into<BoxError>,
84{
85 type Response = A::Response;
86 type Error = BoxError;
87 type Future = ResponseFuture<A::Future, B::Future>;
88
89 fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
90 match self {
91 OptionService::Some(service) => service.poll_ready(cx).map_err(Into::into),
92 OptionService::None(service) => service.poll_ready(cx).map_err(Into::into),
93 }
94 }
95
96 fn call(&mut self, request: Request) -> Self::Future {
97 match self {
98 OptionService::Some(service) => ResponseFuture {
99 kind: Kind::Some {
100 inner: service.call(request),
101 },
102 },
103 OptionService::None(service) => ResponseFuture {
104 kind: Kind::None {
105 inner: service.call(request),
106 },
107 },
108 }
109 }
110}
111
112pin_project! {
113 pub struct ResponseFuture<A, B> {
115 #[pin]
116 kind: Kind<A, B>,
117 }
118}
119
120pin_project! {
121 #[project = KindProj]
122 enum Kind<A, B> {
123 Some { #[pin] inner: A },
124 None { #[pin] inner: B },
125 }
126}
127
128impl<A, B, T, AE, BE> Future for ResponseFuture<A, B>
129where
130 A: Future<Output = Result<T, AE>>,
131 AE: Into<BoxError>,
132 B: Future<Output = Result<T, BE>>,
133 BE: Into<BoxError>,
134{
135 type Output = Result<T, BoxError>;
136
137 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
138 match self.project().kind.project() {
139 KindProj::Some { inner } => inner.poll(cx).map_err(Into::into),
140 KindProj::None { inner } => inner.poll(cx).map_err(Into::into),
141 }
142 }
143}