hyperlane/hook/impl.rs
1use crate::*;
2
3/// A blanket implementation for any function that takes a `Context` and returns a value.
4///
5/// This implementation makes it easy to use any compatible function as a `FnContextSendSync`,
6/// promoting a flexible and functional programming style.
7impl<F, R> FnContextSendSync<R> for F where F: Fn(Context) -> R + Send + Sync {}
8
9/// A blanket implementation for functions that return a pinned, boxed, sendable future.
10///
11/// This trait is a common pattern for asynchronous handlers in Rust, enabling type
12/// erasure and dynamic dispatch for futures. It is essential for storing different
13/// async functions in a collection.
14impl<F, T> FnContextPinBoxSendSync<T> for F where F: FnContextSendSync<SendableAsyncTask<T>> {}
15
16/// A blanket implementation for static, sendable, synchronous functions that return a future.
17///
18/// This trait is used for handlers that are known at compile time, ensuring they
19/// are safe to be sent across threads and have a static lifetime. This is crucial
20/// for handlers that are part of the application's long-lived state.
21impl<F, Fut, T> FnContextSendSyncStatic<Fut, T> for F
22where
23 F: FnContextSendSync<Fut> + 'static,
24 Fut: Future<Output = T> + Send,
25{
26}
27
28/// A blanket implementation for any future that is sendable and has a static lifetime.
29///
30/// This is a convenient trait for working with futures in an asynchronous context,
31/// ensuring that they can be safely managed by the async runtime across different
32/// threads.
33impl<T, R> FutureSendStatic<R> for T where T: Future<Output = R> + Send + 'static {}
34
35/// Blanket implementation of `FutureSend` for any type that satisfies the bounds.
36impl<T, O> FutureSend<O> for T where T: Future<Output = O> + Send {}
37
38/// Blanket implementation of `FnPinBoxFutureSend` for any type that satisfies the bounds.
39impl<T, O> FnPinBoxFutureSend<O> for T where T: Fn() -> SendableAsyncTask<O> + Send + Sync {}
40
41/// Provides a default implementation for `ServerControlHook`.
42impl Default for ServerControlHook {
43 /// Creates a new `ServerControlHook` instance with default no-op hooks.
44 ///
45 /// The default `wait_hook` and `shutdown_hook` do nothing, allowing the server
46 /// to run without specific shutdown or wait logic unless configured otherwise.
47 ///
48 /// # Returns
49 ///
50 /// - `Self` - A new `ServerControlHook` instance with default hooks.
51 #[inline(always)]
52 fn default() -> Self {
53 Self {
54 wait_hook: Arc::new(|| Box::pin(async {})),
55 shutdown_hook: Arc::new(|| Box::pin(async {})),
56 }
57 }
58}
59
60/// Manages server lifecycle hooks, including waiting and shutdown procedures.
61///
62/// This struct holds closures that are executed during specific server lifecycle events.
63impl ServerControlHook {
64 /// Waits for the server's shutdown signal or completion.
65 ///
66 /// This method asynchronously waits until the server's `wait_hook` is triggered,
67 /// typically indicating that the server has finished its operations or is ready to shut down.
68 pub async fn wait(&self) {
69 self.get_wait_hook()().await;
70 }
71
72 /// Initiates the server shutdown process.
73 ///
74 /// This method asynchronously calls the `shutdown_hook`, which is responsible for
75 /// performing any necessary cleanup or graceful shutdown procedures.
76 pub async fn shutdown(&self) {
77 self.get_shutdown_hook()().await;
78 }
79}
80
81/// Implements the `PartialEq` trait for `HookType`.
82///
83/// This allows for comparing two `HookType` instances for equality.
84/// Function pointers are compared using `std::ptr::fn_addr_eq` for reliable comparison.
85impl PartialEq for HookType {
86 /// Checks if two `HookType` instances are equal.
87 ///
88 /// # Arguments
89 ///
90 /// - `&Self` - The other `HookType` instance to compare against.
91 ///
92 /// # Returns
93 ///
94 /// - `bool` - `true` if the instances are equal, `false` otherwise.
95 #[inline(always)]
96 fn eq(&self, other: &Self) -> bool {
97 match (self, other) {
98 (HookType::TaskPanic(order1, factory1), HookType::TaskPanic(order2, factory2)) => {
99 order1 == order2 && std::ptr::fn_addr_eq(*factory1, *factory2)
100 }
101 (
102 HookType::RequestError(order1, factory1),
103 HookType::RequestError(order2, factory2),
104 ) => order1 == order2 && std::ptr::fn_addr_eq(*factory1, *factory2),
105 (
106 HookType::RequestMiddleware(order1, factory1),
107 HookType::RequestMiddleware(order2, factory2),
108 ) => order1 == order2 && std::ptr::fn_addr_eq(*factory1, *factory2),
109 (HookType::Route(path1, factory1), HookType::Route(path2, factory2)) => {
110 path1 == path2 && std::ptr::fn_addr_eq(*factory1, *factory2)
111 }
112 (
113 HookType::ResponseMiddleware(order1, factory1),
114 HookType::ResponseMiddleware(order2, factory2),
115 ) => order1 == order2 && std::ptr::fn_addr_eq(*factory1, *factory2),
116 _ => false,
117 }
118 }
119}
120
121/// Implements the `Eq` trait for `HookType`.
122///
123/// This indicates that `HookType` has a total equality relation.
124impl Eq for HookType {}
125
126/// Implements the `Hash` trait for `HookType`.
127///
128/// This allows `HookType` to be used as a key in hash-based collections.
129/// Function pointers are hashed using their addresses.
130impl Hash for HookType {
131 /// Hashes the `HookType` instance.
132 ///
133 /// # Arguments
134 ///
135 /// - `&mut Hasher` - The hasher to use.
136 #[inline(always)]
137 fn hash<H: Hasher>(&self, state: &mut H) {
138 match self {
139 HookType::TaskPanic(order, factory) => {
140 0u8.hash(state);
141 order.hash(state);
142 (factory as *const fn() -> ServerHookHandler).hash(state);
143 }
144 HookType::RequestError(order, factory) => {
145 1u8.hash(state);
146 order.hash(state);
147 (factory as *const fn() -> ServerHookHandler).hash(state);
148 }
149 HookType::RequestMiddleware(order, factory) => {
150 2u8.hash(state);
151 order.hash(state);
152 (factory as *const fn() -> ServerHookHandler).hash(state);
153 }
154 HookType::Route(path, factory) => {
155 3u8.hash(state);
156 path.hash(state);
157 (factory as *const fn() -> ServerHookHandler).hash(state);
158 }
159 HookType::ResponseMiddleware(order, factory) => {
160 4u8.hash(state);
161 order.hash(state);
162 (factory as *const fn() -> ServerHookHandler).hash(state);
163 }
164 }
165 }
166}
167
168/// Implementation block for `HookType`.
169///
170/// This block defines utility methods associated with the `HookType` enum.
171/// These methods provide additional functionality for working with hooks,
172/// such as extracting the execution order (priority) used in duplicate checks.
173impl HookType {
174 /// Returns the optional execution priority (`order`) of a hook.
175 ///
176 /// Hooks that carry an `order` indicate their execution priority.
177 /// Hooks without an `order` are considered unordered and are ignored in duplicate checks.
178 ///
179 /// # Returns
180 ///
181 /// - `Option<isize>` - `Some(order)` if the hook defines a priority, otherwise `None`.
182 #[inline(always)]
183 pub fn try_get_order(&self) -> Option<isize> {
184 match *self {
185 HookType::RequestMiddleware(order, _)
186 | HookType::ResponseMiddleware(order, _)
187 | HookType::TaskPanic(order, _)
188 | HookType::RequestError(order, _) => order,
189 _ => None,
190 }
191 }
192
193 #[inline(always)]
194 pub fn try_get_hook(&self) -> Option<ServerHookHandlerFactory> {
195 match *self {
196 HookType::RequestMiddleware(_, hook)
197 | HookType::ResponseMiddleware(_, hook)
198 | HookType::TaskPanic(_, hook)
199 | HookType::RequestError(_, hook) => Some(hook),
200 _ => None,
201 }
202 }
203}
204
205/// Implement `ServerHook` for `DefaultServerHook`
206///
207/// This implementation provides default no-op handlers for server hook operations.
208impl ServerHook for DefaultServerHook {
209 /// Creates a new `DefaultServerHook` instance.
210 ///
211 /// # Arguments
212 ///
213 /// - `&Context`: The context object providing server configuration and state
214 ///
215 /// # Returns
216 ///
217 /// - `Self` - A new instance of `DefaultServerHook`
218 async fn new(_: &Context) -> Self {
219 Self
220 }
221
222 /// Handles server hook operations with a no-op implementation.
223 ///
224 /// # Arguments
225 ///
226 /// - `&Context`: The context object providing server configuration and state
227 async fn handle(self, _: &Context) {}
228}