4 releases
0.1.3 | Oct 19, 2022 |
---|---|
0.1.2 | Oct 18, 2022 |
0.1.1 | Oct 18, 2022 |
0.1.0 | Oct 17, 2022 |
#227 in FFI
25 downloads per month
20KB
126 lines
FFI Destruct
Generates destructors for structures that contain raw pointers in the FFI.
About
The Destruct
derive macro will implement Drop
trait and free(drop) memory for structures containing raw pointers.
It may be a common procedure for FFI resource management.
Safety
All the raw pointer dropping operations are unsafe and almost unchecked. Should only drop resources managed by Rust side.
Supported types
Both *const
and *mut
are acceptable.
But currently, only single-level pointers are supported.
type | handler | note |
---|---|---|
* c_char |
::std::ffi::CString::from_raw() |
C-style string. Likely type path: std::ffi::c_char libc::c_char std::os::raw::c_char |
* <T> |
::std::boxed::Box::from_raw() |
Anything heap-allocated by Rust. Something likely from: Box::into_raw(Box::new(<T>)) |
Example
Provides a structure with several raw pointers that need to be dropped manually.
use ffi_destruct::{extern_c_destructor, Destruct};
use std::ffi::*;
#[derive(Destruct)]
pub struct MyStruct {
field: *mut std::ffi::c_char,
}
pub struct AnyOther(u32, u32);
// Struct definition here, with deriving Destruct and nullable attributes.
#[derive(Destruct)]
pub struct Structure {
// Default is non-null.
c_string: *const c_char,
#[nullable]
c_string_nullable: *mut c_char,
other: *mut MyStruct,
#[nullable]
other_nullable: *mut MyStruct,
// Do not drop this field.
#[no_drop]
not_dropped: *const AnyOther,
// Raw pointer for any other things
any: *mut AnyOther,
// Non-pointer types are still available, and will not be added to drop().
pub normal_int: u32,
pub normal_string: String,
}
// (Optional) The macro here generates the destructor: destruct_structure()
extern_c_destructor!(Structure);
fn main() {
// Some resources manually managed
let tmp = AnyOther(1, 1);
let tmp_ptr = Box::into_raw(Box::new(tmp));
let my_struct = Structure {
c_string: CString::new("Hello").unwrap().into_raw(),
c_string_nullable: std::ptr::null_mut(),
other: Box::into_raw(Box::new(MyStruct {
field: CString::new("Hello").unwrap().into_raw(),
})),
other_nullable: std::ptr::null_mut(),
not_dropped: tmp_ptr,
any: Box::into_raw(Box::new(AnyOther(1, 1))),
normal_int: 114514,
normal_string: "Hello".to_string(),
};
let my_struct_ptr = Box::into_raw(Box::new(my_struct));
// FFI calling
unsafe {
destruct_structure(my_struct_ptr);
}
// Drop the manually managed resources
unsafe {
let _ = Box::from_raw(tmp_ptr);
}
}
After expanding the macros:
#[macro_use]
#![feature(prelude_import)]
#![allow(dead_code)]
#[prelude_import]
use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;
use ffi_destruct::{extern_c_destructor, Destruct};
use std::ffi::*;
pub struct MyStruct {
field: *mut std::ffi::c_char,
}
impl ::std::ops::Drop for MyStruct {
fn drop(&mut self) {
unsafe {
let _ = ::std::ffi::CString::from_raw(self.field as *mut ::std::ffi::c_char);
}
}
}
pub struct AnyOther(u32, u32);
pub struct Structure {
c_string: *const c_char,
#[nullable]
c_string_nullable: *mut c_char,
other: *mut MyStruct,
#[nullable]
other_nullable: *mut MyStruct,
#[no_drop]
not_dropped: *const AnyOther,
any: *mut AnyOther,
pub normal_int: u32,
pub normal_string: String,
}
impl ::std::ops::Drop for Structure {
fn drop(&mut self) {
unsafe {
let _ = ::std::ffi::CString::from_raw(
self.c_string as *mut ::std::ffi::c_char,
);
if !self.c_string_nullable.is_null() {
let _ = ::std::ffi::CString::from_raw(
self.c_string_nullable as *mut ::std::ffi::c_char,
);
}
let _ = ::std::boxed::Box::from_raw(self.other as *mut MyStruct);
if !self.other_nullable.is_null() {
let _ = ::std::boxed::Box::from_raw(
self.other_nullable as *mut MyStruct,
);
}
let _ = ::std::boxed::Box::from_raw(self.any as *mut AnyOther);
}
}
}
#[no_mangle]
pub unsafe extern "C" fn destruct_structure(ptr: *mut Structure) {
if ptr.is_null() {
return;
}
let _ = ::std::boxed::Box::from_raw(ptr);
}
fn main() {
let tmp = AnyOther(1, 1);
let tmp_ptr = Box::into_raw(Box::new(tmp));
let my_struct = Structure {
c_string: CString::new("Hello").unwrap().into_raw(),
c_string_nullable: std::ptr::null_mut(),
other: Box::into_raw(
Box::new(MyStruct {
field: CString::new("Hello").unwrap().into_raw(),
}),
),
other_nullable: std::ptr::null_mut(),
not_dropped: tmp_ptr,
any: Box::into_raw(Box::new(AnyOther(1, 1))),
normal_int: 114514,
normal_string: "Hello".to_string(),
};
let my_struct_ptr = Box::into_raw(Box::new(my_struct));
unsafe {
destruct_structure(my_struct_ptr);
}
unsafe {
let _ = Box::from_raw(tmp_ptr);
}
}
Dependencies
~2MB
~42K SLoC