aws_smithy_http_server/plugin/
model_plugins.rs

1/*
2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6// If you make any updates to this file (including Rust docs), make sure you make them to
7// `http_plugins.rs` too!
8
9use crate::plugin::{IdentityPlugin, Plugin, PluginStack};
10
11use super::{LayerPlugin, ModelMarker};
12
13/// A wrapper struct for composing model plugins.
14/// It operates identically to [`HttpPlugins`](crate::plugin::HttpPlugins); see its documentation.
15#[derive(Debug)]
16pub struct ModelPlugins<P>(pub(crate) P);
17
18impl Default for ModelPlugins<IdentityPlugin> {
19    fn default() -> Self {
20        Self(IdentityPlugin)
21    }
22}
23
24impl ModelPlugins<IdentityPlugin> {
25    /// Create an empty [`ModelPlugins`].
26    ///
27    /// You can use [`ModelPlugins::push`] to add plugins to it.
28    pub fn new() -> Self {
29        Self::default()
30    }
31}
32
33impl<P> ModelPlugins<P> {
34    /// Apply a new model plugin after the ones that have already been registered.
35    ///
36    /// ```rust
37    /// use aws_smithy_http_server::plugin::ModelPlugins;
38    /// # use aws_smithy_http_server::plugin::IdentityPlugin as LoggingPlugin;
39    /// # use aws_smithy_http_server::plugin::IdentityPlugin as MetricsPlugin;
40    ///
41    /// let model_plugins = ModelPlugins::new().push(LoggingPlugin).push(MetricsPlugin);
42    /// ```
43    ///
44    /// The plugins' runtime logic is executed in registration order.
45    /// In our example above, `LoggingPlugin` would run first, while `MetricsPlugin` is executed last.
46    ///
47    /// ## Implementation notes
48    ///
49    /// Plugins are applied to the underlying [`Service`](tower::Service) in opposite order compared
50    /// to their registration order.
51    ///
52    /// As an example:
53    ///
54    /// ```rust,compile_fail
55    /// #[derive(Debug)]
56    /// pub struct PrintPlugin;
57    ///
58    /// impl<Ser, Op, S> Plugin<Ser, Op, T> for PrintPlugin
59    /// // [...]
60    /// {
61    ///     // [...]
62    ///     fn apply(&self, inner: T) -> Self::Service {
63    ///         PrintService {
64    ///             inner,
65    ///             service_id: Ser::ID,
66    ///             operation_id: Op::ID
67    ///         }
68    ///     }
69    /// }
70    /// ```
71    // We eagerly require `NewPlugin: ModelMarker`, despite not really needing it, because compiler
72    // errors get _substantially_ better if the user makes a mistake.
73    pub fn push<NewPlugin: ModelMarker>(self, new_plugin: NewPlugin) -> ModelPlugins<PluginStack<NewPlugin, P>> {
74        ModelPlugins(PluginStack::new(new_plugin, self.0))
75    }
76
77    /// Applies a single [`tower::Layer`] to all operations _before_ they are deserialized.
78    pub fn layer<L>(self, layer: L) -> ModelPlugins<PluginStack<LayerPlugin<L>, P>> {
79        ModelPlugins(PluginStack::new(LayerPlugin(layer), self.0))
80    }
81}
82
83impl<Ser, Op, T, InnerPlugin> Plugin<Ser, Op, T> for ModelPlugins<InnerPlugin>
84where
85    InnerPlugin: Plugin<Ser, Op, T>,
86{
87    type Output = InnerPlugin::Output;
88
89    fn apply(&self, input: T) -> Self::Output {
90        self.0.apply(input)
91    }
92}
93
94impl<InnerPlugin> ModelMarker for ModelPlugins<InnerPlugin> where InnerPlugin: ModelMarker {}