Parachutes
If we can't avoid data that must be dropped, it might be possible to attach a parachute to this data to ensure it's dropped safely even if an exception is thrown. When we attach a parachute to data, we move it from Rust to Julia by converting it to managed data, which makes the GC responsible for dropping it.
A parachute can be attached by calling AttachParachute::attach_parachute
, this trait is implemented for any type that is Sized + Send + Sync + 'static
. The resulting WithParachute
derefences to the original type, the parachute can be removed by calling WithParachute::remove_parachute
.
use jlrs::{catch::catch_exceptions, data::managed::parachute::AttachParachute, prelude::*};
fn main() {
let handle = Builder::new().start_local().expect("cannot init Julia");
handle.local_scope::<_, 2>(|mut frame| {
// Safety: this is a POF. We attach a parachute to vec
// to make the GC responsible for dropping it.
unsafe {
catch_exceptions(
|| {
let dims = (usize::MAX, usize::MAX);
let vec = vec![1usize];
let mut with_parachute = vec.attach_parachute(&mut frame);
let arr = TypedArray::<u8>::new_unchecked(&mut frame, dims);
with_parachute.push(2);
arr
},
|e| println!("caught exception: {e:?}"),
)
}
.expect_err("allocated ridiculously-sized array successfully");
});
}
We've attached a parachute to vec
so it's fine that the next line throws an exception. The GC will eventually take care of dropping it for us.