1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
//! Create function pointers backed by Rust closures or callbacks.
//!
//! The function pointers can be used as long as the [`Closure`] or [`DynamicClosure`] they were
//! created from are alive. Attempting to call a function pointer created by a dropped [`Closure`]
//! or [`DynamicClosure`] causes undefined behavior.
//!
//! Closures passed to [`Closure`] must implement `Fn`. They must also be `Send + Sync` because
//! foreign code may pass the generated function pointers to other threads and call the function
//! pointers multiple times concurrently.
//!
//! [`DynamicClosure`] creates function pointers whose signatures are known only at runtime and
//! dispatches calls through a Rust callback. Its callback argument and return helpers are available
//! in the [`dynamic`] module.
//!
//! # Examples
//!
//! ```
//! use fiffi::closure::Closure;
//!
//! let add_value = 1;
//! let add_one = Closure::new(|value: i32| value + add_value);
//!
//! // SAFETY: `add_one` represents an `extern "C"` function that accepts one `i32` and returns an
//! // `i32`. `add_one` remains alive while it is called.
//! let add_one_fn_ptr = unsafe { add_one.as_fn_ptr().into_fn::<extern "C" fn(i32) -> i32>() };
//!
//! assert_eq!(add_one_fn_ptr(1336), 1337);
//! ```
//!
//! Use [`DynamicClosure`] when the function signature is defined at runtime:
//!
//! ```
//! use core::mem::MaybeUninit;
//!
//! use fiffi::closure::DynamicClosure;
//! use fiffi::closure::dynamic::DynamicClosureCall;
//! use fiffi::types::Type;
//!
//! fn callback(mut call: DynamicClosureCall<i32>) {
//! let arg = call
//! .args()
//! .get(0)
//! .expect("This callback must be used with exactly one argument.");
//!
//! if arg.ty() != &Type::I32 {
//! // **NOTE** This will abort instead of unwinding regardless of the crate's setting
//! // because Rust cannot unwind past libffi's `extern "C"` functions.
//! panic!("This callback can only be used with an `i32` argument.");
//! }
//!
//! let mut value = MaybeUninit::<i32>::uninit();
//!
//! // SAFETY: The argument's type is `i32`. The `copy_to` fully initializes `value`.
//! let result = unsafe {
//! arg.copy_to(&mut value);
//! value.assume_init()
//! } + call.context();
//!
//! let ret = call.ret().expect("This callback expects a return value.");
//!
//! if ret.ty() != &Type::I32 {
//! // **NOTE** This will abort instead of unwinding regardless of the crate's setting
//! // because Rust cannot unwind past libffi's `extern "C"` functions.
//! panic!("This callback can only be used with an `i32` return value.");
//! }
//!
//! // SAFETY: The return value's type is `i32`.
//! unsafe {
//! ret.write(result);
//! }
//! }
//!
//! let add_offset = DynamicClosure::new(callback, &[Type::I32], Some(&Type::I32), 5);
//!
//! // SAFETY: `add_offset` represents an `extern "C"` function that accepts one `i32` and returns
//! // an `i32`. `add_offset` remains alive while it is called.
//! let add_offset_fn = unsafe {
//! add_offset
//! .as_fn_ptr()
//! .into_fn::<extern "C" fn(i32) -> i32>()
//! };
//!
//! assert_eq!(add_offset_fn(37), 42);
//! ```
//!
//! # Panics inside of closures
//!
//! If a closure called through [`Closure`] or a callback called through [`DynamicClosure`] panics,
//! the process will abort instead of unwinding regardless of the project's settings. This is
//! because panics cannot unwind across libffi's `extern "C"` functions.
pub
use Debug;
pub use ;
pub use DynamicClosure;
use ;
use crateFnPtr;
use crate;
use crateClosureAllocationError;
use crateCif;
/// Base closure type that handles common code for fiffi's closure types.
// SAFETY: Moving a `BaseClosure` moves only RAII owners for stable heap and libffi allocations.
// Sending it is sound when its payload is `Send`.
unsafe
// SAFETY: A `BaseClosure` exposes only a copyable function pointer and a shared payload reference.
// Sharing it is sound when its payload is `Sync`.
unsafe