surrealdb_core/mac/
mod.rs

1/// A macro that allows lazily parsing a value from the environment variable,
2/// with a fallback default value if the variable is not set or parsing fails.
3///
4/// # Parameters
5///
6/// - `$key`: An expression representing the name of the environment variable.
7/// - `$t`: The type of the value to be parsed.
8/// - `$default`: The default value to fall back to if the environment variable
9///   is not set or parsing fails.
10///
11/// # Return Value
12///
13/// A lazy static variable of type `std::sync::LazyLock`, which holds the parsed value
14/// from the environment variable or the default value.
15#[macro_export]
16macro_rules! lazy_env_parse {
17	// With no default specified
18	($key:expr_2021, Option<String>) => {
19		std::sync::LazyLock::new(|| std::env::var($key).ok())
20	};
21	// With no default specified
22	($key:expr_2021, $t:ty) => {
23		std::sync::LazyLock::new(|| {
24			std::env::var($key).ok().and_then(|s| s.parse::<$t>().ok()).unwrap_or_default()
25		})
26	};
27	// With a closure for the default value
28	($key:expr_2021, $t:ty, || $default:expr_2021) => {
29		std::sync::LazyLock::new(|| {
30			std::env::var($key).ok().and_then(|s| s.parse::<$t>().ok()).unwrap_or_else(|| $default)
31		})
32	};
33	// With a static expression for the default value
34	($key:expr_2021, $t:ty, $default:expr_2021) => {
35		std::sync::LazyLock::new(|| {
36			std::env::var($key).ok().and_then(|s| s.parse::<$t>().ok()).unwrap_or($default)
37		})
38	};
39	// With a closure for the default value, allowing for byte suffixes
40	(bytes, $key:expr_2021, $t:ty, || $default:expr_2021) => {
41		std::sync::LazyLock::new(|| {
42			std::env::var($key)
43				.ok()
44				.and_then(|s| {
45					use $crate::str::ParseBytes;
46					s.parse_bytes::<$t>().ok()
47				})
48				.unwrap_or_else(|| $default)
49		})
50	};
51	// With a static expression for the default value, allowing for byte suffixes
52	(bytes, $key:expr_2021, $t:ty, $default:expr_2021) => {
53		std::sync::LazyLock::new(|| {
54			std::env::var($key)
55				.ok()
56				.and_then(|s| {
57					use $crate::str::ParseBytes;
58					s.parse_bytes::<$t>().ok()
59				})
60				.unwrap_or($default)
61		})
62	};
63}
64
65/// Creates a new b-tree map of key-value pairs.
66///
67/// This macro creates a new map, clones the items
68/// from the secondary map, and inserts additional
69/// items to the new map.
70#[macro_export]
71macro_rules! map {
72    ($($k:expr_2021 $(, if let $grant:pat = $check:expr_2021)? $(, if $guard:expr_2021)? => $v:expr_2021),* $(,)? $( => $x:expr_2021 )?) => {{
73        let mut m = ::std::collections::BTreeMap::new();
74    	$(m.extend($x.iter().map(|(k, v)| (k.clone(), v.clone())));)?
75		$( $(if let $grant = $check)? $(if $guard)? { m.insert($k, $v); };)+
76        m
77    }};
78}
79
80/// Extends a b-tree map of key-value pairs.
81///
82/// This macro extends the supplied map, by cloning
83/// the items from the secondary map into it.
84#[macro_export]
85macro_rules! mrg {
86	($($m:expr_2021, $x:expr_2021)+) => {{
87		$($m.extend($x.iter().map(|(k, v)| (k.clone(), v.clone())));)+
88		$($m)+
89	}};
90}
91
92/// Throws an unreachable error with location details
93macro_rules! fail {
94	($($arg:tt)+) => {
95		$crate::err::Error::Unreachable(format!("{}:{}: {}", file!(), line!(), std::format_args!($($arg)+)))
96	};
97}
98
99/// Converts some text into a new line byte string
100macro_rules! bytes {
101	($expression:expr_2021) => {
102		format!("{}\n", $expression).into_bytes()
103	};
104}
105
106/// Pauses and yields execution to the tokio runtime
107macro_rules! yield_now {
108	() => {
109		if tokio::runtime::Handle::try_current().is_ok() {
110			tokio::task::consume_budget().await;
111		}
112	};
113}
114
115/// Matches on a specific config environment
116macro_rules! get_cfg {
117	($i:ident : $($s:expr_2021),+) => (
118		let $i = || { $( if cfg!($i=$s) { return $s; } );+ "unknown"};
119	)
120}
121
122/// Runs a method on a transaction, ensuring that the transaction
123/// is cancelled and rolled back if the initial function fails.
124/// This can be used to ensure that the use of the `?` operator to
125/// fail fast and return an error from a function does not leave
126/// a transaction in an uncommitted state without rolling back.
127macro_rules! catch {
128	($txn:ident, $default:expr_2021) => {
129		match $default {
130			Err(e) => {
131				let _ = $txn.cancel().await;
132				return Err(e);
133			}
134			Ok(v) => v,
135		}
136	};
137}
138
139/// Runs a method on a transaction, ensuring that the transaction
140/// is cancelled and rolled back if the initial function fails, or
141/// committed successfully if the initial function succeeds. This
142/// can be used to ensure that the use of the `?` operator to fail
143/// fast and return an error from a function does not leave a
144/// transaction in an uncommitted state without rolling back.
145macro_rules! run {
146	($txn:ident, $default:expr_2021) => {
147		match $default {
148			Err(e) => {
149				let _ = $txn.cancel().await;
150				Err(e)
151			}
152			Ok(v) => match $txn.commit().await {
153				Err(e) => {
154					let _ = $txn.cancel().await;
155					Err(e)
156				}
157				Ok(_) => Ok(v),
158			},
159		}
160	};
161}
162
163#[cfg(test)]
164mod test {
165	use crate::err::Error;
166
167	fn fail_func() -> Result<(), Error> {
168		Err(fail!("Reached unreachable code"))
169	}
170
171	fn fail_func_args() -> Result<(), Error> {
172		Err(fail!("Found {} but expected {}", "test", "other"))
173	}
174
175	#[test]
176	fn fail_literal() {
177		let Err(Error::Unreachable(msg)) = fail_func() else {
178			panic!()
179		};
180		assert_eq!("crates/core/src/mac/mod.rs:168: Reached unreachable code", msg);
181	}
182
183	#[test]
184	fn fail_call() {
185		let Error::Unreachable(msg) = Error::unreachable("Reached unreachable code") else {
186			panic!()
187		};
188		assert_eq!("crates/core/src/mac/mod.rs:185: Reached unreachable code", msg);
189	}
190
191	#[test]
192	fn fail_arguments() {
193		let Err(Error::Unreachable(msg)) = fail_func_args() else {
194			panic!()
195		};
196		assert_eq!("crates/core/src/mac/mod.rs:172: Found test but expected other", msg);
197	}
198}