Skip to content

Commit

Permalink
docs: completing docs
Browse files Browse the repository at this point in the history
  • Loading branch information
I-Info committed Oct 18, 2022
1 parent a12156d commit d08adb9
Show file tree
Hide file tree
Showing 3 changed files with 257 additions and 11 deletions.
75 changes: 64 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,42 +24,50 @@ But currently, only single-level pointers are supported.
## Example
Provides a structure with several raw pointers that need to be dropped manually.
```rust
use std::ffi::*;
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 {
c_string: *const c_char,
// 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().
// normal_int: u8,
// normal_string: String,
pub normal_int: u32,
pub normal_string: String,
}

// (Optional) The macro here generates the destructor: destruct_structure()
extern_c_destructor!(Structure);

fn test_struct() {
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));
Expand All @@ -70,9 +78,17 @@ fn test_struct() {
}
```

After expanding the macro:
After expanding the macros:
```rust
// derive(Destruct)
#[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 {
Expand All @@ -81,30 +97,67 @@ impl ::std::ops::Drop for MyStruct {
}
}

// derive(Destruct)
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);
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.other_nullable as *mut MyStruct,
);
}
let _ = ::std::boxed::Box::from_raw(self.any as *mut AnyOther);
}
}
}

// extern_c_destructor!() generates snake_case named destructor
#[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);
}
}
```
52 changes: 52 additions & 0 deletions examples/simple.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
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);
}
}
141 changes: 141 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,146 @@
//! # FFI Destruct
//! Generates destructors for structures that contain raw pointers in the FFI.
//!
//! ## Example
//! Provides a structure with several raw pointers that need to be dropped manually.
//! ```no_run
//! 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 test() {
//! 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:
//! ```ignore
//! #[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);
//! }
//! }
//! ```
use convert_case::{Case, Casing};
use proc_macro2::{Ident, TokenStream};
Expand Down

0 comments on commit d08adb9

Please sign in to comment.