C++
extern "C" {
void query (uchar * * res, size_t * rln)
{
*rln = 20;
*res = new uchar[*rln];
for (size_t i = 0; i < rln; ++i) {
(*res)[i] = 'x';
}
}
void free_res (uchar * res)
{
delete[] res;
}
}
Rust
mod ffi {
use ::libc::{c_uchar, size_t};
extern "C" {
fn query (res: &mut *mut c_uchar, rln: &mut size_t)
;
}
// Create safe API around this:
use ::core::{
convert::TryInto,
ops::{Deref, DerefMut},
ptr,
slice,
};
pub(in super)
struct CppBoxedSlice {
ptr: ptr::NonNull<c_uchar>,
len: usize,
}
impl CppBoxedSlice {
#[inline]
pub
fn from_query () -> Self
{
let mut res: *mut c_uchar = ptr::null_mut();
let mut rln: size_t = 0;
unsafe { query(&mut res, &mut rln); }
let ptr: ptr::NonNull<c_uchar> =
ptr::NonNull::new(ptr)
.expect("Error from `query()`: got NULL ptr")
;
let len: usize =
len .try_into()
.expect("Error from `query()`: `rln` overflowed")
;
Self { ptr, len }
}
}
impl Drop for CppBoxedSlice {
fn drop (self: &'_ mut Self)
{
unsafe { free_res(self.ptr.as_ptr()); }
}
}
impl Deref for CppBoxedSlice {
type Target = [c_uchar];
#[inline]
fn deref (self: &'_ Self) -> &'_ Self::Target
{ unsafe {
slice::from_raw_parts(self.ptr.as_ptr(), self.len)
}}
}
impl DerefMut for CppBoxedSlice {
#[inline]
fn deref_mut (self: &'_ mut Self) -> &'_ mut Self::Target
{ unsafe {
slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len)
}}
}
}
// pub
use ffi::CppBoxedSlice;
let mut result = CppBoxedSlice::from_query(); // <- Owns the allocation -+
let slice: &mut [c_uchar] = &mut *result; // |
/* result.drop(); */ // <-- calls free_res() to deallocate --------------+
1 Like