Skip to content

Commit 08ec188

Browse files
authored
Merge pull request #10 from marioortizmanero/sabi
Support for `abi_stable`
2 parents 46e60ac + b325818 commit 08ec188

File tree

2 files changed

+52
-29
lines changed

2 files changed

+52
-29
lines changed

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ exclude = ["/link_tests"]
1212
rust-version = "1.49" # 1.48 doesn't support `ManuallyDrop` in union.
1313

1414
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
15+
[dependencies]
16+
abi_stable = { version = "0.10", default-features = false, optional = true }
1517

1618
[dev-dependencies]
1719
tokio = { version = "1.4.0", features = ["macros", "rt-multi-thread", "sync", "time"] }

src/lib.rs

Lines changed: 50 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -85,12 +85,11 @@ use std::{
8585
/// Every non-compatible ABI change will increase this number.
8686
pub const ABI_VERSION: u32 = 2;
8787

88-
type PollFn<T> = unsafe extern "C" fn(fut_ptr: *mut (), context_ptr: *mut FfiContext) -> FfiPoll<T>;
89-
9088
/// The FFI compatible [`std::task::Poll`]
9189
///
9290
/// [`std::task::Poll`]: std::task::Poll
9391
#[repr(C, u8)]
92+
#[cfg_attr(feature = "abi_stable", derive(abi_stable::StableAbi))]
9493
pub enum FfiPoll<T> {
9594
/// Represents that a value is immediately ready.
9695
Ready(T),
@@ -128,21 +127,22 @@ impl Drop for DropBomb {
128127
///
129128
/// [`std::task::Context`]: std::task::Context
130129
#[repr(C)]
130+
#[cfg_attr(feature = "abi_stable", derive(abi_stable::StableAbi))]
131131
pub struct FfiContext<'a> {
132132
/// This waker is passed as borrow semantic.
133133
/// The external fn must not `drop` or `wake` it.
134-
waker_ref: *const FfiWaker,
134+
waker: *const FfiWakerBase,
135135
/// Lets the compiler know that this references the FfiWaker and should not outlive it
136-
phantom: PhantomData<&'a FfiWaker>,
136+
_marker: PhantomData<&'a FfiWakerBase>,
137137
}
138138

139139
impl<'a> FfiContext<'a> {
140140
/// SAFETY: VTable functions of `waker` are unsafe, the caller must ensure they have a
141141
/// sane behavior as a Waker. `with_context` relies on this to be safe.
142142
unsafe fn new(waker: &'a FfiWaker) -> Self {
143143
Self {
144-
waker_ref: waker as *const _ as *const FfiWaker,
145-
phantom: PhantomData,
144+
waker: waker as *const FfiWaker as *const FfiWakerBase,
145+
_marker: PhantomData,
146146
}
147147
}
148148

@@ -155,30 +155,30 @@ impl<'a> FfiContext<'a> {
155155
static RUST_WAKER_VTABLE: RawWakerVTable = {
156156
unsafe fn clone(data: *const ()) -> RawWaker {
157157
let waker = data.cast::<FfiWaker>();
158-
let cloned = ((*waker).vtable.clone)(waker);
158+
let cloned = ((*(*waker).base.vtable).clone)(waker.cast());
159159
RawWaker::new(cloned.cast(), &RUST_WAKER_VTABLE)
160160
}
161161
unsafe fn wake(data: *const ()) {
162162
let waker = data.cast::<FfiWaker>();
163-
((*waker).vtable.wake)(waker);
163+
((*(*waker).base.vtable).wake)(waker.cast());
164164
}
165165
unsafe fn wake_by_ref(data: *const ()) {
166166
let waker = data.cast::<FfiWaker>();
167-
((*waker).vtable.wake_by_ref)(waker);
167+
((*(*waker).base.vtable).wake_by_ref)(waker.cast());
168168
}
169169
unsafe fn drop(data: *const ()) {
170170
let waker = data.cast::<FfiWaker>();
171-
((*waker).vtable.drop)(waker);
171+
((*(*waker).base.vtable).drop)(waker.cast());
172172
}
173173
RawWakerVTable::new(clone, wake, wake_by_ref, drop)
174174
};
175175

176-
// SAFETY: `waker_ref`'s vtable functions must have behavior, this is the contract of
176+
// SAFETY: `waker`'s vtable functions must have behavior, this is the contract of
177177
// `FfiContext::new`.
178178
let waker = unsafe {
179-
// The `waker_ref` is borrowed from external context. We must not call drop on it.
179+
// The waker reference is borrowed from external context. We must not call drop on it.
180180
ManuallyDrop::new(Waker::from_raw(RawWaker::new(
181-
self.waker_ref.cast(),
181+
self.waker.cast(),
182182
&RUST_WAKER_VTABLE,
183183
)))
184184
};
@@ -201,11 +201,14 @@ pub trait ContextExt {
201201
impl<'a> ContextExt for Context<'a> {
202202
fn with_ffi_context<T, F: FnOnce(&mut FfiContext) -> T>(&mut self, closure: F) -> T {
203203
static C_WAKER_VTABLE_OWNED: FfiWakerVTable = {
204-
unsafe extern "C" fn clone(data: *const FfiWaker) -> *const FfiWaker {
204+
unsafe extern "C" fn clone(data: *const FfiWakerBase) -> *const FfiWakerBase {
205205
DropBomb::with("Waker::clone", || {
206+
let data = data as *mut FfiWaker;
206207
let waker: Waker = (*(*data).waker.owned).clone();
207208
Box::into_raw(Box::new(FfiWaker {
208-
vtable: &C_WAKER_VTABLE_OWNED,
209+
base: FfiWakerBase {
210+
vtable: &C_WAKER_VTABLE_OWNED,
211+
},
209212
waker: WakerUnion {
210213
owned: ManuallyDrop::new(waker),
211214
},
@@ -215,19 +218,20 @@ impl<'a> ContextExt for Context<'a> {
215218
}
216219
// In this case, we must own `data`. This can only happen when the `data` pointer is returned from `clone`.
217220
// Thus the it is `Box<FfiWaker>`.
218-
unsafe extern "C" fn wake(data: *const FfiWaker) {
221+
unsafe extern "C" fn wake(data: *const FfiWakerBase) {
219222
DropBomb::with("Waker::wake", || {
220223
let b = Box::from_raw(data as *mut FfiWaker);
221224
ManuallyDrop::into_inner(b.waker.owned).wake();
222225
})
223226
}
224-
unsafe extern "C" fn wake_by_ref(data: *const FfiWaker) {
227+
unsafe extern "C" fn wake_by_ref(data: *const FfiWakerBase) {
225228
DropBomb::with("Waker::wake_by_ref", || {
229+
let data = data as *mut FfiWaker;
226230
(*data).waker.owned.wake_by_ref();
227231
})
228232
}
229233
// Same as `wake`.
230-
unsafe extern "C" fn drop(data: *const FfiWaker) {
234+
unsafe extern "C" fn drop(data: *const FfiWakerBase) {
231235
DropBomb::with("Waker::drop", || {
232236
let mut b = Box::from_raw(data as *mut FfiWaker);
233237
ManuallyDrop::drop(&mut b.waker.owned);
@@ -243,24 +247,28 @@ impl<'a> ContextExt for Context<'a> {
243247
};
244248

245249
static C_WAKER_VTABLE_REF: FfiWakerVTable = {
246-
unsafe extern "C" fn clone(data: *const FfiWaker) -> *const FfiWaker {
250+
unsafe extern "C" fn clone(data: *const FfiWakerBase) -> *const FfiWakerBase {
247251
DropBomb::with("Waker::clone", || {
252+
let data = data as *mut FfiWaker;
248253
let waker: Waker = (*(*data).waker.reference).clone();
249254
Box::into_raw(Box::new(FfiWaker {
250-
vtable: &C_WAKER_VTABLE_OWNED,
255+
base: FfiWakerBase {
256+
vtable: &C_WAKER_VTABLE_OWNED,
257+
},
251258
waker: WakerUnion {
252259
owned: ManuallyDrop::new(waker),
253260
},
254261
}))
255262
.cast()
256263
})
257264
}
258-
unsafe extern "C" fn wake_by_ref(data: *const FfiWaker) {
265+
unsafe extern "C" fn wake_by_ref(data: *const FfiWakerBase) {
259266
DropBomb::with("Waker::wake_by_ref", || {
267+
let data = data as *mut FfiWaker;
260268
(*(*data).waker.reference).wake_by_ref();
261269
})
262270
}
263-
unsafe extern "C" fn unreachable(_: *const FfiWaker) {
271+
unsafe extern "C" fn unreachable(_: *const FfiWakerBase) {
264272
std::process::abort();
265273
}
266274
FfiWakerVTable {
@@ -272,7 +280,9 @@ impl<'a> ContextExt for Context<'a> {
272280
};
273281

274282
let waker = FfiWaker {
275-
vtable: &C_WAKER_VTABLE_REF,
283+
base: FfiWakerBase {
284+
vtable: &C_WAKER_VTABLE_REF,
285+
},
276286
waker: WakerUnion {
277287
reference: self.waker(),
278288
},
@@ -287,9 +297,17 @@ impl<'a> ContextExt for Context<'a> {
287297
}
288298

289299
// Inspired by Gary Guo (github.com/nbdd0121)
300+
//
301+
// The base is what can be accessed through FFI, and the regular struct contains
302+
// internal data (the original waker).
303+
#[repr(C)]
304+
#[cfg_attr(feature = "abi_stable", derive(abi_stable::StableAbi))]
305+
struct FfiWakerBase {
306+
vtable: *const FfiWakerVTable,
307+
}
290308
#[repr(C)]
291309
struct FfiWaker {
292-
vtable: &'static FfiWakerVTable,
310+
base: FfiWakerBase,
293311
waker: WakerUnion,
294312
}
295313

@@ -302,17 +320,19 @@ union WakerUnion {
302320

303321
#[derive(PartialEq, Eq, Hash, Clone, Copy)]
304322
#[repr(C)]
323+
#[cfg_attr(feature = "abi_stable", derive(abi_stable::StableAbi))]
305324
struct FfiWakerVTable {
306-
clone: unsafe extern "C" fn(*const FfiWaker) -> *const FfiWaker,
307-
wake: unsafe extern "C" fn(*const FfiWaker),
308-
wake_by_ref: unsafe extern "C" fn(*const FfiWaker),
309-
drop: unsafe extern "C" fn(*const FfiWaker),
325+
clone: unsafe extern "C" fn(*const FfiWakerBase) -> *const FfiWakerBase,
326+
wake: unsafe extern "C" fn(*const FfiWakerBase),
327+
wake_by_ref: unsafe extern "C" fn(*const FfiWakerBase),
328+
drop: unsafe extern "C" fn(*const FfiWakerBase),
310329
}
311330

312331
/// The FFI compatible future type with `Send` bound.
313332
///
314333
/// See [module level documentation](index.html) for more details.
315334
#[repr(transparent)]
335+
#[cfg_attr(feature = "abi_stable", derive(abi_stable::StableAbi))]
316336
pub struct BorrowingFfiFuture<'a, T>(LocalBorrowingFfiFuture<'a, T>);
317337

318338
/// The FFI compatible future type with `Send` bound and `'static` lifetime,
@@ -427,9 +447,10 @@ impl<T> Future for BorrowingFfiFuture<'_, T> {
427447
///
428448
/// See [module level documentation](index.html) for more details.
429449
#[repr(C)]
450+
#[cfg_attr(feature = "abi_stable", derive(abi_stable::StableAbi))]
430451
pub struct LocalBorrowingFfiFuture<'a, T> {
431452
fut_ptr: *mut (),
432-
poll_fn: PollFn<T>,
453+
poll_fn: unsafe extern "C" fn(fut_ptr: *mut (), context_ptr: *mut FfiContext) -> FfiPoll<T>,
433454
drop_fn: unsafe extern "C" fn(*mut ()),
434455
_marker: PhantomData<&'a ()>,
435456
}

0 commit comments

Comments
 (0)