aws_smithy_http_server/operation/
handler.rs

1/*
2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6use std::{
7    convert::Infallible,
8    future::Future,
9    marker::PhantomData,
10    task::{Context, Poll},
11};
12
13use futures_util::{future::Map, FutureExt};
14use tower::Service;
15
16use super::OperationShape;
17
18/// A utility trait used to provide an even interface for all operation handlers.
19///
20/// See [`operation`](crate::operation) documentation for more info.
21pub trait Handler<Op, Exts>
22where
23    Op: OperationShape,
24{
25    type Future: Future<Output = Result<Op::Output, Op::Error>>;
26
27    fn call(&mut self, input: Op::Input, exts: Exts) -> Self::Future;
28}
29
30/// A utility trait used to provide an even interface over return types `Result<Ok, Error>`/`Ok`.
31trait IntoResult<Ok, Error> {
32    fn into_result(self) -> Result<Ok, Error>;
33}
34
35// We can convert from `Result<Ok, Error>` to `Result<Ok, Error>`.
36impl<Ok, Error> IntoResult<Ok, Error> for Result<Ok, Error> {
37    fn into_result(self) -> Result<Ok, Error> {
38        self
39    }
40}
41
42// We can convert from `T` to `Result<T, Infallible>`.
43impl<Ok> IntoResult<Ok, Infallible> for Ok {
44    fn into_result(self) -> Result<Ok, Infallible> {
45        Ok(self)
46    }
47}
48
49// fn(Input) -> Output
50impl<Op, F, Fut> Handler<Op, ()> for F
51where
52    Op: OperationShape,
53    F: Fn(Op::Input) -> Fut,
54    Fut: Future,
55    Fut::Output: IntoResult<Op::Output, Op::Error>,
56{
57    type Future = Map<Fut, fn(Fut::Output) -> Result<Op::Output, Op::Error>>;
58
59    fn call(&mut self, input: Op::Input, _exts: ()) -> Self::Future {
60        (self)(input).map(IntoResult::into_result)
61    }
62}
63
64// fn(Input, Ext_i) -> Output
65macro_rules! impl_handler {
66    ($($var:ident),+) => (
67        impl<Op, F, Fut, $($var,)*> Handler<Op, ($($var,)*)> for F
68        where
69            Op: OperationShape,
70            F: Fn(Op::Input, $($var,)*) -> Fut,
71            Fut: Future,
72            Fut::Output: IntoResult<Op::Output, Op::Error>,
73        {
74            type Future = Map<Fut, fn(Fut::Output) -> Result<Op::Output, Op::Error>>;
75
76            fn call(&mut self, input: Op::Input, exts: ($($var,)*)) -> Self::Future {
77                #[allow(non_snake_case)]
78                let ($($var,)*) = exts;
79                (self)(input, $($var,)*).map(IntoResult::into_result)
80            }
81        }
82    )
83}
84
85impl_handler!(Exts0);
86impl_handler!(Exts0, Exts1);
87impl_handler!(Exts0, Exts1, Exts2);
88impl_handler!(Exts0, Exts1, Exts2, Exts3);
89impl_handler!(Exts0, Exts1, Exts2, Exts3, Exts4);
90impl_handler!(Exts0, Exts1, Exts2, Exts3, Exts4, Exts5);
91impl_handler!(Exts0, Exts1, Exts2, Exts3, Exts4, Exts5, Exts6);
92impl_handler!(Exts0, Exts1, Exts2, Exts3, Exts4, Exts5, Exts6, Exts7);
93impl_handler!(Exts0, Exts1, Exts2, Exts3, Exts4, Exts5, Exts6, Exts7, Exts8);
94
95/// An extension trait for [`Handler`].
96pub trait HandlerExt<Op, Exts>: Handler<Op, Exts>
97where
98    Op: OperationShape,
99{
100    /// Convert the [`Handler`] into a [`Service`].
101    fn into_service(self) -> IntoService<Op, Self>
102    where
103        Self: Sized,
104    {
105        IntoService {
106            handler: self,
107            _operation: PhantomData,
108        }
109    }
110}
111
112impl<Op, Exts, H> HandlerExt<Op, Exts> for H
113where
114    Op: OperationShape,
115    H: Handler<Op, Exts>,
116{
117}
118
119/// A [`Service`] provided for every [`Handler`].
120pub struct IntoService<Op, H> {
121    pub(crate) handler: H,
122    pub(crate) _operation: PhantomData<Op>,
123}
124
125impl<Op, H> Clone for IntoService<Op, H>
126where
127    H: Clone,
128{
129    fn clone(&self) -> Self {
130        Self {
131            handler: self.handler.clone(),
132            _operation: PhantomData,
133        }
134    }
135}
136
137impl<Op, Exts, H> Service<(Op::Input, Exts)> for IntoService<Op, H>
138where
139    Op: OperationShape,
140    H: Handler<Op, Exts>,
141{
142    type Response = Op::Output;
143    type Error = Op::Error;
144    type Future = H::Future;
145
146    fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
147        Poll::Ready(Ok(()))
148    }
149
150    fn call(&mut self, (input, exts): (Op::Input, Exts)) -> Self::Future {
151        self.handler.call(input, exts)
152    }
153}