use std::cell::Cell;
pub(crate) struct AssumeFailed;
pub(crate) struct StopTest;
pub(crate) struct LoopDone;
pub(crate) struct InvalidArgument(pub(crate) String);
pub(crate) struct InternalError(pub(crate) String);
pub(crate) fn raise_control<T: std::any::Any + Send>(payload: T) -> ! {
std::panic::resume_unwind(Box::new(payload))
}
#[track_caller]
pub(crate) fn raise_internal_error(message: std::fmt::Arguments<'_>) -> ! {
let location = std::panic::Location::caller();
let full = format!(
"Internal error in hegel at {location}: {message}. This is a bug in hegel \
itself; please report it at https://github.com/hegeldev/hegel-rust/issues"
);
if currently_in_test_context() {
raise_control(InternalError(full));
} else {
panic!("{full}");
}
}
macro_rules! hegel_internal_assert {
($cond:expr $(,)?) => {
if $cond {
} else {
$crate::control::raise_internal_error(::std::format_args!(
"internal assertion failed: {}",
::std::stringify!($cond)
));
}
};
($cond:expr, $($arg:tt)+) => {
if $cond {
} else {
$crate::control::raise_internal_error(::std::format_args!($($arg)+));
}
};
}
pub(crate) use hegel_internal_assert;
macro_rules! hegel_internal_assert_eq {
($left:expr, $right:expr $(,)?) => {
match (&$left, &$right) {
(left, right) => $crate::control::hegel_internal_assert!(
left == right,
"internal assertion failed: {} == {} (left: {:?}, right: {:?})",
::std::stringify!($left),
::std::stringify!($right),
left,
right
),
}
};
}
pub(crate) use hegel_internal_assert_eq;
macro_rules! hegel_internal_error {
($($arg:tt)+) => {
$crate::control::raise_internal_error(::std::format_args!($($arg)+))
};
}
pub(crate) use hegel_internal_error;
thread_local! {
static IN_TEST_CONTEXT: Cell<bool> = const { Cell::new(false) };
}
#[doc(hidden)]
pub(crate) fn with_test_context<R>(f: impl FnOnce() -> R) -> R {
struct Restore(bool);
impl Drop for Restore {
fn drop(&mut self) {
IN_TEST_CONTEXT.set(self.0);
}
}
let _restore = Restore(IN_TEST_CONTEXT.get());
IN_TEST_CONTEXT.set(true);
f()
}
pub fn currently_in_test_context() -> bool {
IN_TEST_CONTEXT.get()
}
#[cfg(test)]
#[path = "../tests/embedded/control_tests.rs"]
mod tests;