surrealdb_core/mac/
mod.rsmacro_rules! fail {
($($arg:tt)+) => {
$crate::err::Error::Unreachable(format!("{}:{}: {}", file!(), line!(), std::format_args!($($arg)+)))
};
}
macro_rules! bytes {
($expression:expr) => {
format!("{}\n", $expression).into_bytes()
};
}
macro_rules! map {
($($k:expr $(, if let $grant:pat = $check:expr)? $(, if $guard:expr)? => $v:expr),* $(,)? $( => $x:expr )?) => {{
let mut m = ::std::collections::BTreeMap::new();
$(m.extend($x.iter().map(|(k, v)| (k.clone(), v.clone())));)?
$( $(if let $grant = $check)? $(if $guard)? { m.insert($k, $v); };)+
m
}};
}
macro_rules! mrg {
($($m:expr, $x:expr)+) => {{
$($m.extend($x.iter().map(|(k, v)| (k.clone(), v.clone())));)+
$($m)+
}};
}
macro_rules! get_cfg {
($i:ident : $($s:expr),+) => (
let $i = || { $( if cfg!($i=$s) { return $s; } );+ "unknown"};
)
}
macro_rules! catch {
($txn:ident, $default:expr) => {
match $default {
Err(e) => {
let _ = $txn.cancel().await;
return Err(e);
}
Ok(v) => v,
}
};
}
macro_rules! run {
($txn:ident, $default:expr) => {
match $default {
Err(e) => {
let _ = $txn.cancel().await;
Err(e)
}
Ok(v) => match $txn.commit().await {
Err(e) => {
let _ = $txn.cancel().await;
Err(e)
}
Ok(_) => Ok(v),
},
}
};
}
#[macro_export]
macro_rules! lazy_env_parse {
($key:expr, $t:ty) => {
std::sync::LazyLock::new(|| {
std::env::var($key)
.and_then(|s| Ok(s.parse::<$t>().unwrap_or_default()))
.unwrap_or_default()
})
};
($key:expr, $t:ty, $default:expr) => {
std::sync::LazyLock::new(|| {
std::env::var($key)
.and_then(|s| Ok(s.parse::<$t>().unwrap_or($default)))
.unwrap_or($default)
})
};
}
#[macro_export]
macro_rules! lazy_env_parse_or_else {
($key:expr, $t:ty, $default:expr) => {
std::sync::LazyLock::new(|| {
std::env::var($key)
.and_then(|s| Ok(s.parse::<$t>().unwrap_or_else($default)))
.unwrap_or_else($default)
})
};
}
#[cfg(test)]
macro_rules! async_defer{
(let $bind:ident = ($capture:expr) defer { $($d:tt)* } after { $($t:tt)* }) => {
async {
async_defer!(@captured);
async_defer!(@catch_unwind);
#[allow(unused_mut)]
let mut v = Some($capture);
#[allow(unused_mut)]
let mut $bind = Captured(&mut v);
let res = CatchUnwindFuture(async { $($t)* }).await;
#[allow(unused_variables,unused_mut)]
if let Some(mut $bind) = v.take(){
async { $($d)* }.await;
}
match res{
Ok(x) => x,
Err(e) => ::std::panic::resume_unwind(e)
}
}
};
(defer { $($d:tt)* } after { $($t:tt)* }) => {
async {
async_defer!(@catch_unwind);
let res = CatchUnwindFuture(async { $($t)* }).await;
#[allow(unused_variables)]
async { $($d)* }.await;
match res{
Ok(x) => x,
Err(e) => ::std::panic::resume_unwind(e)
}
}
};
(@captured) => {
pub struct Captured<'a,T>(&'a mut Option<T>);
impl<T> ::std::ops::Deref for Captured<'_,T>{
type Target = T;
fn deref(&self) -> &T{
self.0.as_ref().unwrap()
}
}
impl<T> ::std::ops::DerefMut for Captured<'_,T>{
fn deref_mut(&mut self) -> &mut T{
self.0.as_mut().unwrap()
}
}
impl<T> Captured<'_,T>{
#[allow(dead_code)]
pub fn take(self) -> T{
self.0.take().unwrap()
}
}
};
(@catch_unwind) => {
struct CatchUnwindFuture<F>(F);
impl<F,R> ::std::future::Future for CatchUnwindFuture<F>
where F: ::std::future::Future<Output = R>,
{
type Output = ::std::thread::Result<R>;
fn poll(self: ::std::pin::Pin<&mut Self>, cx: &mut ::std::task::Context) -> ::std::task::Poll<Self::Output>{
let pin = unsafe{ self.map_unchecked_mut(|x| &mut x.0) };
match ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(||{
pin.poll(cx)
})) {
Ok(x) => x.map(Ok),
Err(e) => ::std::task::Poll::Ready(Err(e))
}
}
}
};
}
#[cfg(test)]
mod test {
use crate::err::Error;
#[tokio::test]
async fn async_defer_basic() {
let mut counter = 0;
async_defer!(defer {
assert_eq!(counter,1);
} after {
assert_eq!(counter,0);
counter += 1;
})
.await;
async_defer!(let t = (()) defer {
panic!("shouldn't be called");
} after {
assert_eq!(counter,1);
counter += 1;
t.take();
})
.await;
}
#[tokio::test]
#[should_panic(expected = "this is should be the message of the panic")]
async fn async_defer_panic() {
let mut counter = 0;
async_defer!(defer {
assert_eq!(counter,1);
panic!("this is should be the message of the panic")
} after {
assert_eq!(counter,0);
counter += 1;
panic!("this panic should be caught")
})
.await;
}
#[test]
fn fail_literal() {
let Error::Unreachable(msg) = fail!("Reached unreachable code") else {
panic!()
};
assert_eq!("core/src/mac/mod.rs:263: Reached unreachable code", msg);
}
#[test]
fn fail_arguments() {
let Error::Unreachable(msg) = fail!("Found {} but expected {}", "test", "other") else {
panic!()
};
assert_eq!("core/src/mac/mod.rs:271: Found test but expected other", msg);
}
}