hermit/
macros.rs

1/// Prints to the standard output.
2///
3/// Adapted from [`std::print`].
4///
5/// [`std::print`]: https://doc.rust-lang.org/stable/std/macro.print.html
6#[cfg(target_os = "none")]
7#[macro_export]
8macro_rules! print {
9    ($($arg:tt)*) => {{
10        $crate::console::_print(::core::format_args!($($arg)*));
11    }};
12}
13
14/// Prints to the standard output, with a newline.
15///
16/// Adapted from [`std::println`].
17///
18/// [`std::println`]: https://doc.rust-lang.org/stable/std/macro.println.html
19#[cfg(target_os = "none")]
20#[macro_export]
21macro_rules! println {
22    () => {
23        $crate::print!("\n")
24    };
25    ($($arg:tt)*) => {{
26        $crate::console::_print(::core::format_args!("{}\n", format_args!($($arg)*)));
27    }};
28}
29
30/// Emergency output.
31#[cfg(target_os = "none")]
32#[macro_export]
33macro_rules! panic_println {
34    () => {{
35        $crate::console::_panic_print(::core::format_args!("\n"));
36    }};
37    ($($arg:tt)*) => {{
38        $crate::console::_panic_print(::core::format_args!("{}\n", format_args!($($arg)*)));
39    }};
40}
41
42#[cfg(not(target_os = "none"))]
43#[macro_export]
44macro_rules! panic_println {
45    ($($arg:tt)*) => {
46        println!($($arg)*);
47    };
48}
49
50/// Prints and returns the value of a given expression for quick and dirty
51/// debugging.
52// Copied from std/macros.rs
53#[cfg(target_os = "none")]
54#[macro_export]
55macro_rules! dbg {
56    // NOTE: We cannot use `concat!` to make a static string as a format argument
57    // of `eprintln!` because `file!` could contain a `{` or
58    // `$val` expression could be a block (`{ .. }`), in which case the `eprintln!`
59    // will be malformed.
60    () => {
61        $crate::println!("[{}:{}]", ::core::file!(), ::core::line!())
62    };
63    ($val:expr $(,)?) => {
64        // Use of `match` here is intentional because it affects the lifetimes
65        // of temporaries - https://stackoverflow.com/a/48732525/1063961
66        match $val {
67            tmp => {
68                $crate::println!("[{}:{}] {} = {:#?}",
69                    ::core::file!(), ::core::line!(), ::core::stringify!($val), &tmp);
70                tmp
71            }
72        }
73    };
74    ($($val:expr),+ $(,)?) => {
75        ($($crate::dbg!($val)),+,)
76    };
77}
78
79cfg_if::cfg_if! {
80	if #[cfg(not(any(
81		target_arch = "riscv64",
82		feature = "common-os"
83	)))] {
84		/// Runs `f` on the kernel stack.
85		///
86		/// All arguments and return values have to fit into registers:
87		///
88		/// ```
89		/// assert!(mem::size_of::<T>() <= mem::size_of::<usize>());
90		/// ```
91		///
92		/// When working with bigger types, manually route the data over pointers:
93		///
94		/// ```
95		/// f(&arg1, &mut ret);
96		/// // instead of
97		/// let ret = f(arg);
98		/// ```
99		#[allow(unused_macro_rules)]
100		macro_rules! kernel_function {
101			($f:ident()) => {{
102				// This propagates any unsafety requirements of `f` to the caller.
103				if false {
104					$f();
105				}
106
107				#[allow(unreachable_code)]
108				#[allow(unused_unsafe)]
109				unsafe {
110					$crate::arch::switch::kernel_function0($f)
111				}
112			}};
113
114			($f:ident($arg1:expr)) => {{
115				// This propagates any unsafety requirements of `f` to the caller.
116				if false {
117					$f($arg1);
118				}
119
120				#[allow(unreachable_code)]
121				#[allow(unused_unsafe)]
122				unsafe {
123					$crate::arch::switch::kernel_function1($f, $arg1)
124				}
125			}};
126
127			($f:ident($arg1:expr, $arg2:expr)) => {{
128				// This propagates any unsafety requirements of `f` to the caller.
129				if false {
130					$f($arg1, $arg2);
131				}
132
133				#[allow(unreachable_code)]
134				#[allow(unused_unsafe)]
135				unsafe {
136					$crate::arch::switch::kernel_function2($f, $arg1, $arg2)
137				}
138			}};
139
140			($f:ident($arg1:expr, $arg2:expr, $arg3:expr)) => {{
141				// This propagates any unsafety requirements of `f` to the caller.
142				if false {
143					$f($arg1, $arg2, $arg3);
144				}
145
146				#[allow(unreachable_code)]
147				#[allow(unused_unsafe)]
148				unsafe {
149					$crate::arch::switch::kernel_function3($f, $arg1, $arg2, $arg3)
150				}
151			}};
152
153			($f:ident($arg1:expr, $arg2:expr, $arg3:expr, $arg4:expr)) => {{
154				// This propagates any unsafety requirements of `f` to the caller.
155				if false {
156					$f($arg1, $arg2, $arg3, $arg4);
157				}
158
159				#[allow(unreachable_code)]
160				#[allow(unused_unsafe)]
161				unsafe {
162					$crate::arch::switch::kernel_function4($f, $arg1, $arg2, $arg3, $arg4)
163				}
164			}};
165
166			($f:ident($arg1:expr, $arg2:expr, $arg3:expr, $arg4:expr, $arg5:expr)) => {{
167				// This propagates any unsafety requirements of `f` to the caller.
168				if false {
169					$f($arg1, $arg2, $arg3, $arg4, $arg5);
170				}
171
172				#[allow(unreachable_code)]
173				#[allow(unused_unsafe)]
174				unsafe {
175					$crate::arch::switch::kernel_function5($f, $arg1, $arg2, $arg3, $arg4, $arg5)
176				}
177			}};
178
179			($f:ident($arg1:expr, $arg2:expr, $arg3:expr, $arg4:expr, $arg5:expr, $arg6:expr)) => {{
180				// This propagates any unsafety requirements of `f` to the caller.
181				if false {
182					$f($arg1, $arg2, $arg3, $arg4, $arg5, $arg6);
183				}
184
185				#[allow(unreachable_code)]
186				#[allow(unused_unsafe)]
187				unsafe {
188					$crate::arch::switch::kernel_function6($f, $arg1, $arg2, $arg3, $arg4, $arg5, $arg6)
189				}
190			}};
191		}
192	} else {
193		// TODO: Switch kernel stack on RISC-V
194		macro_rules! kernel_function {
195			($f:ident($($x:tt)*)) => {{
196				$f($($x)*)
197			}};
198		}
199	}
200}
201
202/// Returns the value of the specified environment variable.
203///
204/// The value is fetched from the current runtime environment and, if not
205/// present, falls back to the same environment variable set at compile time
206/// (might not be present as well).
207#[allow(unused_macros)]
208macro_rules! hermit_var {
209	($name:expr) => {{
210		use alloc::borrow::Cow;
211
212		match crate::env::var($name) {
213			Some(val) => Some(Cow::from(val)),
214			None => option_env!($name).map(Cow::Borrowed),
215		}
216	}};
217}
218
219/// Tries to fetch the specified environment variable with a default value.
220///
221/// Fetches according to [`hermit_var`] or returns the specified default value.
222#[allow(unused_macros)]
223macro_rules! hermit_var_or {
224	($name:expr, $default:expr) => {
225		hermit_var!($name).as_deref().unwrap_or($default)
226	};
227}