surrealdb_core/mac/
mod.rs1macro_rules! fail {
3 ($($arg:tt)+) => {
4 $crate::err::Error::Unreachable(format!("{}:{}: {}", file!(), line!(), std::format_args!($($arg)+)))
5 };
6}
7
8macro_rules! bytes {
10 ($expression:expr) => {
11 format!("{}\n", $expression).into_bytes()
12 };
13}
14
15macro_rules! yield_now {
17 () => {
18 if tokio::runtime::Handle::try_current().is_ok() {
19 tokio::task::yield_now().await;
20 }
21 };
22}
23
24macro_rules! map {
26 ($($k:expr $(, if let $grant:pat = $check:expr)? $(, if $guard:expr)? => $v:expr),* $(,)? $( => $x:expr )?) => {{
27 let mut m = ::std::collections::BTreeMap::new();
28 $(m.extend($x.iter().map(|(k, v)| (k.clone(), v.clone())));)?
29 $( $(if let $grant = $check)? $(if $guard)? { m.insert($k, $v); };)+
30 m
31 }};
32}
33
34macro_rules! mrg {
36 ($($m:expr, $x:expr)+) => {{
37 $($m.extend($x.iter().map(|(k, v)| (k.clone(), v.clone())));)+
38 $($m)+
39 }};
40}
41
42macro_rules! get_cfg {
44 ($i:ident : $($s:expr),+) => (
45 let $i = || { $( if cfg!($i=$s) { return $s; } );+ "unknown"};
46 )
47}
48
49macro_rules! catch {
55 ($txn:ident, $default:expr) => {
56 match $default {
57 Err(e) => {
58 let _ = $txn.cancel().await;
59 return Err(e);
60 }
61 Ok(v) => v,
62 }
63 };
64}
65
66macro_rules! run {
73 ($txn:ident, $default:expr) => {
74 match $default {
75 Err(e) => {
76 let _ = $txn.cancel().await;
77 Err(e)
78 }
79 Ok(v) => match $txn.commit().await {
80 Err(e) => {
81 let _ = $txn.cancel().await;
82 Err(e)
83 }
84 Ok(_) => Ok(v),
85 },
86 }
87 };
88}
89
90#[macro_export]
105macro_rules! lazy_env_parse {
106 ($key:expr, $t:ty) => {
107 std::sync::LazyLock::new(|| {
108 std::env::var($key)
109 .and_then(|s| Ok(s.parse::<$t>().unwrap_or_default()))
110 .unwrap_or_default()
111 })
112 };
113 ($key:expr, $t:ty, $default:expr) => {
114 std::sync::LazyLock::new(|| {
115 std::env::var($key)
116 .and_then(|s| Ok(s.parse::<$t>().unwrap_or($default)))
117 .unwrap_or($default)
118 })
119 };
120}
121
122#[macro_export]
135macro_rules! lazy_env_parse_or_else {
136 ($key:expr, $t:ty, $default:expr) => {
137 std::sync::LazyLock::new(|| {
138 std::env::var($key)
139 .and_then(|s| Ok(s.parse::<$t>().unwrap_or_else($default)))
140 .unwrap_or_else($default)
141 })
142 };
143}
144
145#[cfg(test)]
146macro_rules! async_defer{
147 (let $bind:ident = ($capture:expr) defer { $($d:tt)* } after { $($t:tt)* }) => {
148 async {
149 async_defer!(@captured);
150 async_defer!(@catch_unwind);
151
152 #[allow(unused_mut)]
153 let mut v = Some($capture);
154 #[allow(unused_mut)]
155 let mut $bind = Captured(&mut v);
156 let res = CatchUnwindFuture(async { $($t)* }).await;
157 #[allow(unused_variables,unused_mut)]
158 if let Some(mut $bind) = v.take(){
159 async { $($d)* }.await;
160 }
161 match res{
162 Ok(x) => x,
163 Err(e) => ::std::panic::resume_unwind(e)
164 }
165
166 }
167 };
168
169 (defer { $($d:tt)* } after { $($t:tt)* }) => {
170 async {
171 async_defer!(@catch_unwind);
172
173 let res = CatchUnwindFuture(async { $($t)* }).await;
174 #[allow(unused_variables)]
175 async { $($d)* }.await;
176 match res{
177 Ok(x) => x,
178 Err(e) => ::std::panic::resume_unwind(e)
179 }
180
181 }
182 };
183
184 (@captured) => {
185 pub struct Captured<'a,T>(&'a mut Option<T>);
187 impl<T> ::std::ops::Deref for Captured<'_,T>{
188 type Target = T;
189
190 fn deref(&self) -> &T{
191 self.0.as_ref().unwrap()
192 }
193 }
194 impl<T> ::std::ops::DerefMut for Captured<'_,T>{
195 fn deref_mut(&mut self) -> &mut T{
196 self.0.as_mut().unwrap()
197 }
198 }
199 impl<T> Captured<'_,T>{
200 #[allow(dead_code)]
201 pub fn take(self) -> T{
202 self.0.take().unwrap()
203 }
204 }
205 };
206
207 (@catch_unwind) => {
208 struct CatchUnwindFuture<F>(F);
209 impl<F,R> ::std::future::Future for CatchUnwindFuture<F>
210 where F: ::std::future::Future<Output = R>,
211 {
212 type Output = ::std::thread::Result<R>;
213
214 fn poll(self: ::std::pin::Pin<&mut Self>, cx: &mut ::std::task::Context) -> ::std::task::Poll<Self::Output>{
215 let pin = unsafe{ self.map_unchecked_mut(|x| &mut x.0) };
216 match ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(||{
217 pin.poll(cx)
218 })) {
219 Ok(x) => x.map(Ok),
220 Err(e) => ::std::task::Poll::Ready(Err(e))
221 }
222 }
223 }
224 };
225}
226
227macro_rules! match_insensitive {
229 ($s:expr, { $($p:literal => $e:expr,)* _ => $fe:expr $(,)? }) => {{
230 let s = $s.to_lowercase();
231 $(if s == $p.to_lowercase() { $e }
232 else)* { $fe }
233 }};
234}
235
236#[cfg(test)]
237mod test {
238 use crate::err::Error;
239
240 #[tokio::test]
241 async fn async_defer_basic() {
242 let mut counter = 0;
243
244 async_defer!(defer {
245 assert_eq!(counter,1);
246 } after {
247 assert_eq!(counter,0);
248 counter += 1;
249 })
250 .await;
251
252 async_defer!(let t = (()) defer {
253 panic!("shouldn't be called");
254 } after {
255 assert_eq!(counter,1);
256 counter += 1;
257 t.take();
258 })
259 .await;
260 }
261
262 #[tokio::test]
263 #[should_panic(expected = "this is should be the message of the panic")]
264 async fn async_defer_panic() {
265 let mut counter = 0;
266
267 async_defer!(defer {
268 assert_eq!(counter,1);
270 panic!("this is should be the message of the panic")
271 } after {
272 assert_eq!(counter,0);
273 counter += 1;
274 panic!("this panic should be caught")
275 })
276 .await;
277 }
278
279 #[test]
280 fn fail_literal() {
281 let Error::Unreachable(msg) = fail!("Reached unreachable code") else {
282 panic!()
283 };
284 assert_eq!("crates/core/src/mac/mod.rs:281: Reached unreachable code", msg);
285 }
286
287 #[test]
288 fn fail_arguments() {
289 let Error::Unreachable(msg) = fail!("Found {} but expected {}", "test", "other") else {
290 panic!()
291 };
292 assert_eq!("crates/core/src/mac/mod.rs:289: Found test but expected other", msg);
293 }
294}