Skip to content

Commit

Permalink
merge pull request #13 from sonodima/chore/closure-ret-val
Browse files Browse the repository at this point in the history
pass return values from the closure to the caller
  • Loading branch information
sonodima authored Oct 3, 2024
2 parents b1a8ffc + f467cbd commit 215be04
Showing 1 changed file with 42 additions and 15 deletions.
57 changes: 42 additions & 15 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#![cfg_attr(not(feature = "std"), no_std)]
use core::ffi::c_void;
use core::{ffi::c_void, mem::MaybeUninit};

mod code;
mod exception;
Expand Down Expand Up @@ -40,16 +40,34 @@ where
}
}

fn do_execute_proc<F>(mut closure: F) -> Result<(), Exception>
where
F: FnMut(),
{
let mut exception = Exception::empty();
let closure = &mut closure as *mut _ as *mut c_void;

unsafe {
match handler_stub(handled_proc::<F>, closure, &mut exception) {
MS_CATCHED => Err(exception),
MS_DISABLED => panic!("exception handling is not supported in this build of microseh"),
/* MS_SUCCEEDED */ _ => Ok(()),
}
}
}

/// Executes the provided closure in a context where exceptions are handled, catching any\
/// hardware exceptions that occur.
///
/// Any value returned by the closure is returned by this function, if no exceptions occur.
///
/// # Arguments
///
/// * `closure` - The closure or function to be executed within the handled context.
///
/// # Returns
///
/// * `Ok(())` - If the closure executed without throwing any exceptions.
/// * `Ok(R)` - If the closure executed without throwing any exceptions.
/// * `Err(Exception)` - If an exception occurred during the execution of the closure.
///
/// # Examples
Expand All @@ -67,7 +85,7 @@ where
/// # Caveats
///
/// If an exception occours within the closure, resources that require cleanup via\
/// the `Drop` trait, may not be properly released.
/// the `Drop` trait, will not be released.
///
/// As a rule of thumb, it's recommended not to define resources that implement\
/// the `Drop` trait inside the closure. Instead, allocate and manage these resources\
Expand All @@ -77,20 +95,17 @@ where
///
/// If exception handling is disabled in the build, which occurs when the library is\
/// not built on Windows with Microsoft Visual C++.
pub fn try_seh<F>(mut closure: F) -> Result<(), Exception>
pub fn try_seh<F, R>(mut closure: F) -> Result<R, Exception>
where
F: FnMut(),
F: FnMut() -> R,
{
let mut exception = Exception::empty();
let closure = &mut closure as *mut _ as *mut c_void;

unsafe {
match handler_stub(handled_proc::<F>, closure, &mut exception) {
MS_CATCHED => Err(exception),
MS_DISABLED => panic!("exception handling is not supported in this build of microseh"),
/* MS_SUCCEEDED */ _ => Ok(()),
}
}
let mut ret_val = MaybeUninit::<R>::uninit();
do_execute_proc(|| {
ret_val.write(closure());
})
// SAFETY: We should only reach this point if the inner closure has returned
// without throwing an exception, so `ret_val` should be initialized.
.map(|_| unsafe { ret_val.assume_init() })
}

#[cfg(test)]
Expand Down Expand Up @@ -230,4 +245,16 @@ mod tests {

assert_eq!(ex.unwrap_err().registers().x0(), 0xbadc0debabefffff);
}

#[test]
fn ret_vals() {
let a = try_seh(|| 1337);
assert_eq!(a.unwrap(), 1337);

let b = try_seh(|| "hello");
assert_eq!(b.unwrap(), "hello");

let c = try_seh(|| {});
assert_eq!(core::mem::size_of_val(&c.unwrap()), 0x0);
}
}

0 comments on commit 215be04

Please sign in to comment.