Skip to main content

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}