aws_smithy_http_server/plugin/
closure.rs

1/*
2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6use crate::service::ContainsOperation;
7
8use super::Plugin;
9
10/// An adapter to convert a `Fn(ShapeId, T) -> Service` closure into a [`Plugin`]. See [`plugin_from_operation_fn`] for more details.
11pub struct OperationFn<F> {
12    f: F,
13}
14
15impl<Ser, Op, T, NewService, F> Plugin<Ser, Op, T> for OperationFn<F>
16where
17    Ser: ContainsOperation<Op>,
18    F: Fn(Ser::Operations, T) -> NewService,
19{
20    type Output = NewService;
21
22    fn apply(&self, input: T) -> Self::Output {
23        (self.f)(Ser::VALUE, input)
24    }
25}
26
27/// Constructs a [`Plugin`] using a closure over the [`ServiceShape::] `F: Fn(ShapeId, T) -> Service`.
28///
29/// # Example
30///
31/// ```rust
32/// # use aws_smithy_http_server::{service::*, operation::OperationShape, plugin::Plugin, shape_id::ShapeId};
33/// # pub enum Operation { CheckHealth, GetPokemonSpecies }
34/// # impl Operation { fn shape_id(&self) -> ShapeId { ShapeId::new("", "", "") }}
35/// # pub struct CheckHealth;
36/// # pub struct GetPokemonSpecies;
37/// # pub struct PokemonService;
38/// # impl ServiceShape for PokemonService {
39/// #   const ID: ShapeId = ShapeId::new("", "", "");
40/// #   const VERSION: Option<&'static str> = None;
41/// #   type Protocol = ();
42/// #   type Operations = Operation;
43/// # }
44/// # impl OperationShape for CheckHealth { const ID: ShapeId = ShapeId::new("", "", ""); type Input = (); type Output = (); type Error = (); }
45/// # impl OperationShape for GetPokemonSpecies { const ID: ShapeId = ShapeId::new("", "", ""); type Input = (); type Output = (); type Error = (); }
46/// # impl ContainsOperation<CheckHealth> for PokemonService { const VALUE: Operation = Operation::CheckHealth; }
47/// # impl ContainsOperation<GetPokemonSpecies> for PokemonService { const VALUE: Operation = Operation::GetPokemonSpecies; }
48/// use aws_smithy_http_server::plugin::plugin_from_operation_fn;
49/// use tower::layer::layer_fn;
50///
51/// struct FooService<S> {
52///     info: String,
53///     inner: S
54/// }
55///
56/// fn map<S>(op: Operation, inner: S) -> FooService<S> {
57///     match op {
58///         Operation::CheckHealth => FooService { info: op.shape_id().name().to_string(), inner },
59///         Operation::GetPokemonSpecies => FooService { info: "bar".to_string(), inner },
60///         _ => todo!()
61///     }
62/// }
63///
64/// // This plugin applies the `FooService` middleware around every operation.
65/// let plugin = plugin_from_operation_fn(map);
66/// # let _ = Plugin::<PokemonService, CheckHealth, ()>::apply(&plugin, ());
67/// # let _ = Plugin::<PokemonService, GetPokemonSpecies, ()>::apply(&plugin, ());
68/// ```
69pub fn plugin_from_operation_fn<F>(f: F) -> OperationFn<F> {
70    OperationFn { f }
71}