surrealdb_core/mac/
mod.rs

1/// Converts some text into a new line byte string
2#[macro_export]
3#[doc(hidden)]
4macro_rules! bytes {
5	($expression:expr) => {
6		format!("{}\n", $expression).into_bytes()
7	};
8}
9
10/// Creates a new b-tree map of key-value pairs
11#[macro_export]
12#[doc(hidden)]
13macro_rules! map {
14    ($($k:expr => $v:expr),* $(,)? $( => $x:expr )?) => {{
15        let mut m = ::std::collections::BTreeMap::new();
16        $(m.extend($x.iter().map(|(k, v)| (k.clone(), v.clone())));)?
17        $(m.insert($k, $v);)+
18        m
19    }};
20}
21
22/// Matches on a specific config environment
23#[macro_export]
24#[doc(hidden)]
25macro_rules! get_cfg {
26	($i:ident : $($s:expr),+) => (
27		let $i = || { $( if cfg!($i=$s) { return $s; } );+ "unknown"};
28	)
29}
30
31/// A macro that allows lazily parsing a value from the environment variable,
32/// with a fallback default value if the variable is not set or parsing fails.
33///
34/// # Parameters
35///
36/// - `$key`: An expression representing the name of the environment variable.
37/// - `$t`: The type of the value to be parsed.
38/// - `$default`: The default value to fall back to if the environment variable
39///   is not set or parsing fails.
40///
41/// # Return Value
42///
43/// A lazy static variable of type `once_cell::sync::Lazy`, which holds the parsed value
44/// from the environment variable or the default value.
45#[macro_export]
46macro_rules! lazy_env_parse {
47	($key:expr, $t:ty, $default:expr) => {
48		once_cell::sync::Lazy::new(|| {
49			std::env::var($key)
50				.and_then(|s| Ok(s.parse::<$t>().unwrap_or($default)))
51				.unwrap_or($default)
52		})
53	};
54}
55
56/// Lazily parses an environment variable into a specified type. If the environment variable is not set or the parsing fails,
57/// it returns a default value.
58///
59/// # Parameters
60///
61/// - `$key`: A string literal representing the name of the environment variable.
62/// - `$t`: The type to parse the environment variable into.
63/// - `$default`: A fallback function or constant value to be returned if the environment variable is not set or the parsing fails.
64///
65/// # Returns
66///
67/// A `Lazy` static variable that stores the parsed value or the default value.
68#[macro_export]
69macro_rules! lazy_env_parse_or_else {
70	($key:expr, $t:ty, $default:expr) => {
71		once_cell::sync::Lazy::new(|| {
72			std::env::var($key)
73				.and_then(|s| Ok(s.parse::<$t>().unwrap_or_else($default)))
74				.unwrap_or_else($default)
75		})
76	};
77}
78
79#[cfg(test)]
80#[macro_export]
81macro_rules! async_defer{
82	(let $bind:ident = ($capture:expr) defer { $($d:tt)* } after { $($t:tt)* }) => {
83		async {
84			async_defer!(@captured);
85			async_defer!(@catch_unwind);
86
87			#[allow(unused_mut)]
88			let mut v = Some($capture);
89			#[allow(unused_mut)]
90			let mut $bind = Captured(&mut v);
91			let res = CatchUnwindFuture(async { $($t)* }).await;
92			#[allow(unused_variables,unused_mut)]
93			if let Some(mut $bind) = v.take(){
94				async { $($d)* }.await;
95			}
96			match res{
97				Ok(x) => x,
98				Err(e) => ::std::panic::resume_unwind(e)
99			}
100
101		}
102	};
103
104	(defer { $($d:tt)* } after { $($t:tt)* }) => {
105		async {
106			async_defer!(@catch_unwind);
107
108			let res = CatchUnwindFuture(async { $($t)* }).await;
109			#[allow(unused_variables)]
110			async { $($d)* }.await;
111			match res{
112				Ok(x) => x,
113				Err(e) => ::std::panic::resume_unwind(e)
114			}
115
116		}
117	};
118
119	(@captured) => {
120		// unwraps are save cause the value can only be taken by consuming captured.
121		pub struct Captured<'a,T>(&'a mut Option<T>);
122		impl<T> ::std::ops::Deref for Captured<'_,T>{
123			type Target = T;
124
125			fn deref(&self) -> &T{
126				self.0.as_ref().unwrap()
127			}
128		}
129		impl<T> ::std::ops::DerefMut for Captured<'_,T>{
130			fn deref_mut(&mut self) -> &mut T{
131				self.0.as_mut().unwrap()
132			}
133		}
134		impl<T> Captured<'_,T>{
135			#[allow(dead_code)]
136			pub fn take(self) -> T{
137				self.0.take().unwrap()
138			}
139		}
140	};
141
142	(@catch_unwind) => {
143		struct CatchUnwindFuture<F>(F);
144		impl<F,R> ::std::future::Future for CatchUnwindFuture<F>
145			where F: ::std::future::Future<Output = R>,
146		{
147			type Output = ::std::thread::Result<R>;
148
149			fn poll(self: ::std::pin::Pin<&mut Self>, cx: &mut ::std::task::Context<'_>) -> ::std::task::Poll<Self::Output>{
150				let pin = unsafe{ self.map_unchecked_mut(|x| &mut x.0) };
151				match ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(||{
152					pin.poll(cx)
153				})) {
154					Ok(x) => x.map(Ok),
155					Err(e) => ::std::task::Poll::Ready(Err(e))
156				}
157			}
158		}
159	};
160}
161
162#[cfg(test)]
163mod test {
164	#[tokio::test]
165	async fn async_defer_basic() {
166		let mut counter = 0;
167
168		async_defer!(defer {
169			assert_eq!(counter,1);
170		} after {
171			assert_eq!(counter,0);
172			counter += 1;
173		})
174		.await;
175
176		async_defer!(let t = (()) defer {
177			panic!("shouldn't be called");
178		} after {
179			assert_eq!(counter,1);
180			counter += 1;
181			t.take();
182		})
183		.await;
184	}
185
186	#[tokio::test]
187	#[should_panic(expected = "this is should be the message of the panic")]
188	async fn async_defer_panic() {
189		let mut counter = 0;
190
191		async_defer!(defer {
192			// This should still execute
193			assert_eq!(counter,1);
194			panic!("this is should be the message of the panic")
195		} after {
196			assert_eq!(counter,0);
197			counter += 1;
198			panic!("this panic should be caught")
199		})
200		.await;
201	}
202}