traceback_error/set_callback.rs
1use std::future::Future;
2use std::pin::Pin;
3
4use crate::{TracebackError, TRACEBACK_ERROR_CALLBACK};
5
6pub trait TracebackCallback {
7 fn call(&self, error: TracebackError);
8}
9
10// Define a trait that represents a function returning a Future
11pub trait TracebackCallbackAsync {
12 fn call(&self, error: TracebackError) -> Pin<Box<dyn Future<Output = ()> + Send + Sync>>;
13}
14
15pub enum TracebackCallbackType {
16 Async(Box<dyn TracebackCallbackAsync + Send + Sync>),
17 Sync(Box<dyn TracebackCallback + Send + Sync>),
18}
19
20pub fn set_traceback_callback(callback: TracebackCallbackType) {
21 unsafe {
22 TRACEBACK_ERROR_CALLBACK = Some(callback);
23 }
24}
25
26pub fn reset_traceback_callback() {
27 unsafe {
28 TRACEBACK_ERROR_CALLBACK = None;
29 }
30}
31
32/// Sets a custom traceback callback for error handling in a Rust program.
33///
34/// This macro allows you to define and set a custom traceback callback function,
35/// which will be called when a TracebackError goes out of scope.
36/// The traceback callback provides a way to customize how error information is
37/// handled and reported.
38///
39/// # Usage
40///
41/// To use this macro, provide the name of the callback function you want to use
42/// as the custom traceback callback. This function should take an argument of
43/// type `traceback_error::TracebackError`. The macro generates a unique
44/// struct and function to wrap your callback and sets it as the traceback
45/// callback using `traceback_error::set_traceback_callback`.
46///
47/// # Example
48///
49/// ```rust
50/// // Define a custom traceback callback function
51/// fn my_traceback_callback(error: traceback_error::TracebackError) {
52/// // Custom error handling logic here
53/// println!("Custom traceback callback called: {:?}", error);
54/// }
55///
56/// // Use the set_traceback macro to set the custom traceback callback
57/// traceback_error::set_traceback!(my_traceback_callback);
58///
59/// // Any TracebackErrors will now be handled by my_traceback_callback when dropped
60/// ```
61///
62/// ```rust
63/// // The same is possible with asynchronous functions
64/// async fn my_traceback_callback(error: traceback_error::TracebackError) {
65/// // Custom error handling logic here
66/// println!("Async custom traceback callback called: {:?}", error);
67/// }
68///
69/// // But you have to specify that it is asynchronous
70/// traceback_error::set_traceback!(async my_traceback_callback);
71/// ```
72#[macro_export]
73macro_rules! set_traceback {
74 ($callback:ident) => {
75 $crate::paste::unique_paste! {
76 // Generate a unique identifier for the struct
77 #[allow(non_camel_case_types)]
78 mod [<_private_ $callback _ TempStruct>] {
79 pub struct [<$callback _ TempStruct>];
80
81 impl $crate::set_callback::TracebackCallback for [<$callback _ TempStruct>] {
82 fn call(&self, error: $crate::TracebackError) {
83 super::$callback(error)
84 }
85 }
86 }
87
88 // Expose the generated struct through a function
89 pub fn [<$callback _ temp_struct>]() -> [<_private_ $callback _ TempStruct>]::[<$callback _ TempStruct>] {
90 [<_private_ $callback _ TempStruct>]::[<$callback _ TempStruct>]
91 }
92
93 // Call the macro to set the traceback callback
94 $crate::set_callback::set_traceback_callback($crate::set_callback::TracebackCallbackType::Sync(Box::new([<$callback _ temp_struct>]())));
95 }
96 };
97 (async $callback:ident) => {
98 $crate::paste::unique_paste! {
99 // Generate a unique identifier for the struct
100 #[allow(non_camel_case_types)]
101 mod [<_private_ $callback _ TempStruct>] {
102 pub struct [<$callback _ TempStruct>];
103
104 impl $crate::set_callback::TracebackCallbackAsync for [<$callback _ TempStruct>] {
105 fn call(
106 &self,
107 error: $crate::TracebackError,
108 ) -> std::pin::Pin<
109 Box<dyn std::future::Future<Output = ()> + std::marker::Send + std::marker::Sync>,
110 > {
111 Box::pin(super::$callback(error))
112 }
113 }
114 }
115
116 // Expose the generated struct through a function
117 pub fn [<$callback _ temp_struct>]() -> [<_private_ $callback _ TempStruct>]::[<$callback _ TempStruct>] {
118 [<_private_ $callback _ TempStruct>]::[<$callback _ TempStruct>]
119 }
120
121 // Call the macro to set the traceback callback
122 $crate::set_callback::set_traceback_callback($crate::set_callback::TracebackCallbackType::Async(Box::new([<$callback _ temp_struct>]())));
123 }
124 };
125}