Skip to content

Generates destructors for structures that contain raw pointers in the FFI.

License

Notifications You must be signed in to change notification settings

I-Info/FFI-Destruct

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

17 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

FFI Destruct

crates badge docs badge build badge

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 structure memory operations.

Supported types

Both *const and *mut are acceptable. But currently, only single-level pointers are supported.

  • * c_char: c-style string, using std::ffi::CString::from_raw() to handle std::ffi::CString::into_raw()
  • * <T>: Using std::boxed::Box::from_raw() to handle std::boxed::Box::into_raw()

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,

    // 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() {
    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(),
        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);
    }
}

After expanding the macros:

#[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,
    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 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(),
        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);
    }
}

About

Generates destructors for structures that contain raw pointers in the FFI.

Topics

Resources

License

Stars

Watchers

Forks

Languages