FFI wrappers are especially where I want it, because thatâs where you can end up with a bunch of similar-looking functions that actually differ very slightly in safety considerations.
pub unsafe fn extract_compute_0d(&mut self, name: &str) -> FailResult<f64>
{
let it = self.extract_compute_any_d(name,
ComputeStyle::Global,
ComputeType::Scalar)?;
Some(it.clone())
}
pub unsafe fn extract_compute_1d(
&mut self,
name: &str,
style: ComputeStyle,
len: usize,
) -> FailResult<Vec<f64>>
{
let it = self.extract_compute_any_d(name,
style,
ComputeType::Vector)?;
::std::slice::from_raw_parts(it, len)
.iter().map(|&c| c as f64).collect()
}
When I ask myself the question, why are these functions unsafe, I see the first one, and realize, âoh, itâs because I call this functionâ⊠and then when I look at the second one, my eyes see the same function being called again and stop searching.
It takes careful reading for me to notice that the second line has another unsafe call, and thus stronger requirements to validate.
Edit: And in fact, it has a bug, now that I am looking at it. extract_compute_any_d returns a for<'a> &'a T, which points to uninitialized data if len = 0.