4个版本
0.1.3 | 2022年10月19日 |
---|---|
0.1.2 | 2022年10月18日 |
0.1.1 | 2022年10月18日 |
0.1.0 | 2022年10月17日 |
#191 在 FFI
每月25次下载
20KB
126 代码行
FFI Destruct
为在FFI中包含原始指针的结构生成析构函数。
关于
Destruct
derive宏将实现Drop
特质并为包含原始指针的结构释放(释放)内存。这可能是FFI资源管理的一种常见程序。
安全性
所有原始指针释放操作都是不安全的且几乎未经检查。应仅释放由Rust端管理的资源。
支持类型
接受*const
和*mut
。但当前仅支持单级指针。
类型 | 处理程序 | 注意 |
---|---|---|
* c_char |
::std::ffi::CString::from_raw() |
C风格字符串。可能的类型路径std::ffi::c_char libc::c_char std::os::raw::c_char |
* <T> |
::std::boxed::Box::from_raw() |
Rust堆分配的任何内容。可能来自Box::into_raw(Box::new(<T>)) |
示例
提供了一个包含需要手动释放的几个原始指针的结构。
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);
}
}
在宏展开之后
#[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);
}
}
依赖
~2MB
~43K SLoC