aws_smithy_http_server/plugin/
scoped.rs1use std::marker::PhantomData;
7
8use super::{HttpMarker, ModelMarker, Plugin};
9
10pub struct True;
14
15pub struct False;
19
20pub trait ConditionalApply<Ser, Op, Pl, T> {
24 type Service;
25
26 fn apply(plugin: &Pl, svc: T) -> Self::Service;
27}
28
29impl<Ser, Op, Pl, T> ConditionalApply<Ser, Op, Pl, T> for True
30where
31 Pl: Plugin<Ser, Op, T>,
32{
33 type Service = Pl::Output;
34
35 fn apply(plugin: &Pl, input: T) -> Self::Service {
36 plugin.apply(input)
37 }
38}
39
40impl<P, Op, Pl, T> ConditionalApply<P, Op, Pl, T> for False {
41 type Service = T;
42
43 fn apply(_plugin: &Pl, input: T) -> Self::Service {
44 input
45 }
46}
47
48pub struct Scoped<Scope, Pl> {
74 scope: PhantomData<Scope>,
75 plugin: Pl,
76}
77
78impl<Pl> Scoped<(), Pl> {
79 pub fn new<Scope>(plugin: Pl) -> Scoped<Scope, Pl> {
81 Scoped {
82 scope: PhantomData,
83 plugin,
84 }
85 }
86}
87
88pub trait Membership<Op> {
90 type Contains;
91}
92
93impl<Ser, Op, T, Scope, Pl> Plugin<Ser, Op, T> for Scoped<Scope, Pl>
94where
95 Scope: Membership<Op>,
96 Scope::Contains: ConditionalApply<Ser, Op, Pl, T>,
97{
98 type Output = <Scope::Contains as ConditionalApply<Ser, Op, Pl, T>>::Service;
99
100 fn apply(&self, input: T) -> Self::Output {
101 <Scope::Contains as ConditionalApply<Ser, Op, Pl, T>>::apply(&self.plugin, input)
102 }
103}
104
105impl<Scope, Pl> HttpMarker for Scoped<Scope, Pl> where Pl: HttpMarker {}
106impl<Scope, Pl> ModelMarker for Scoped<Scope, Pl> where Pl: ModelMarker {}
107
108#[macro_export]
131macro_rules! scope {
132 (
133 $(#[$attrs:meta])*
134 $vis:vis struct $name:ident {
135 includes: [$($include:ty),*],
136 excludes: [$($exclude:ty),*]
137 }
138 ) => {
139 $(#[$attrs])*
140 $vis struct $name;
141
142 $(
143 impl $crate::plugin::scoped::Membership<$include> for $name {
144 type Contains = $crate::plugin::scoped::True;
145 }
146 )*
147 $(
148 impl $crate::plugin::scoped::Membership<$exclude> for $name {
149 type Contains = $crate::plugin::scoped::False;
150 }
151 )*
152 };
153}
154
155#[cfg(test)]
156mod tests {
157 use crate::plugin::Plugin;
158
159 use super::Scoped;
160
161 struct OperationA;
162 struct OperationB;
163
164 scope! {
165 pub struct AuthScope {
167 includes: [OperationA],
168 excludes: [OperationB]
169 }
170 }
171
172 struct MockPlugin;
173
174 impl<P, Op> Plugin<P, Op, u32> for MockPlugin {
175 type Output = String;
176
177 fn apply(&self, svc: u32) -> Self::Output {
178 svc.to_string()
179 }
180 }
181
182 #[test]
183 fn scope() {
184 let plugin = MockPlugin;
185 let scoped_plugin = Scoped::new::<AuthScope>(plugin);
186
187 let out: String = Plugin::<(), OperationA, _>::apply(&scoped_plugin, 3_u32);
188 assert_eq!(out, "3".to_string());
189 let out: u32 = Plugin::<(), OperationB, _>::apply(&scoped_plugin, 3_u32);
190 assert_eq!(out, 3);
191 }
192}