I have some code that, when simplified, looks like:
fn foo() -> Vec<u8> {
unsafe {
unsafe_iterator().map(|n| wrap_element(n)).collect()
}
}
The iterator returns items that would be invalidated if the underlying data changed. Sadly, I'm unable to rely on the normal Rust mechanism of mut
here (I'm doing some... odd things).
To rectify the unsafe-ness, I traverse the iterator all at once and make copies of each item (via wrap_element
) and then throw it all into a Vec
. This works because nothing else has a chance to come in and modify the underlying data.
The code works as-is now, but since I use this idiom a few times, I wanted to DRY up my code a bit:
fn zap<F>(f: F) -> Vec<u8>
where F: FnOnce() -> UnsafeIter
{
f().map(|n| wrap_element(n)).collect()
}
fn foo() -> Vec<u8> {
zap(|| unsafe { unsafe_iterator() }) // Unsafe block
}
My problem with this solution is that the call to unsafe_iterator
is unsafe, and it's the wrap_element
/ collect
that makes it safe again. The way that the code is structured does not convey that at all.
I'd like to somehow mark my closure as being unsafe
and then it's zap
s responsibility to make it safe again.
It's not possible to create an unsafe
closure in the same vein as an unsafe fn
, since closures are just anonymous types with implementations of the Fn
, FnMut
, and/or FnOnce
family of traits. Since those traits do not have unsafe
methods, it's not possible to create a closure which is unsafe
to call.
You could create a second set of closure traits with unsafe
methods, then write implementations for those, but you would lose much of the closure sugar.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With