Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ jobs:
MIRIFLAGS: -Zmiri-strict-provenance

minimal:
name: MSRV 1.56
name: MSRV 1.60
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
Expand All @@ -85,7 +85,7 @@ jobs:
- name: Install Rust
run: |
rustup update --no-self-update nightly
rustup default 1.56
rustup default 1.60

- run: cargo +nightly generate-lockfile -Z minimal-versions

Expand Down
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ license = "MIT"
repository = "https://github.com/oxalica/async-ffi"
readme = "README.md"
exclude = ["/link_tests", "/.github"]
rust-version = "1.56" # syn 2 requires edition 2021
rust-version = "1.60" # stabby needs 1.60

[dependencies]
abi_stable = { version = "0.11", default-features = false, optional = true }
abi_stable = { version = "0.11.3", default-features = false, optional = true }
macros = { version = "0.5", package = "async-ffi-macros", path = "./macros", optional = true }
stabby = { version = "72.1.1", optional = true }

[dev-dependencies]
tokio = { version = "1", features = ["macros", "rt-multi-thread", "sync", "time"] }
Expand Down
48 changes: 30 additions & 18 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,8 @@ use std::{
#[cfg_attr(docsrs, doc(cfg(feature = "macros")))]
pub use macros::async_ffi;

use self::private::{FfiWakerBase, FfiWakerVTable};

/// The ABI version of [`FfiFuture`] and all variants.
/// Every non-compatible ABI change will increase this number, as well as the crate major version.
pub const ABI_VERSION: u32 = 2;
Expand All @@ -152,6 +154,7 @@ pub const ABI_VERSION: u32 = 2;
/// [`std::task::Poll`]: std::task::Poll
#[repr(C, u8)]
#[cfg_attr(feature = "abi_stable", derive(abi_stable::StableAbi))]
#[cfg_attr(feature = "stabby", stabby::stabby)]
pub enum FfiPoll<T> {
/// Represents that a value is immediately ready.
Ready(T),
Expand Down Expand Up @@ -190,6 +193,7 @@ impl Drop for DropBomb {
/// [`std::task::Context`]: std::task::Context
#[repr(C)]
#[cfg_attr(feature = "abi_stable", derive(abi_stable::StableAbi))]
#[cfg_attr(feature = "stabby", stabby::stabby)]
pub struct FfiContext<'a> {
/// This waker is passed as borrow semantic.
/// The external fn must not `drop` or `wake` it.
Expand Down Expand Up @@ -358,15 +362,31 @@ impl ContextExt for Context<'_> {
}
}

// Inspired by Gary Guo (github.com/nbdd0121)
//
// The base is what can be accessed through FFI, and the regular struct contains
// internal data (the original waker).
#[repr(C)]
#[cfg_attr(feature = "abi_stable", derive(abi_stable::StableAbi))]
struct FfiWakerBase {
vtable: *const FfiWakerVTable,
mod private {
// Inspired by Gary Guo (github.com/nbdd0121)
//
// The base is what can be accessed through FFI, and the regular struct contains
// internal data (the original waker).
#[repr(C)]
#[cfg_attr(feature = "abi_stable", derive(abi_stable::StableAbi))]
#[cfg_attr(feature = "stabby", stabby::stabby)]
pub struct FfiWakerBase {
pub(super) vtable: *const FfiWakerVTable<Self>,
}

#[derive(Clone, Copy)]
#[repr(C)]
#[cfg_attr(feature = "abi_stable", derive(abi_stable::StableAbi))]
#[cfg_attr(feature = "stabby", stabby::stabby)]
// why `T` here: break the type checking cycle
pub struct FfiWakerVTable<T = FfiWakerBase> {
pub(super) clone: unsafe extern "C" fn(*const T) -> *const T,
pub(super) wake: unsafe extern "C" fn(*const T),
pub(super) wake_by_ref: unsafe extern "C" fn(*const T),
pub(super) drop: unsafe extern "C" fn(*const T),
}
}

#[repr(C)]
struct FfiWaker {
base: FfiWakerBase,
Expand All @@ -380,21 +400,12 @@ union WakerUnion {
unknown: (),
}

#[derive(Clone, Copy)]
#[repr(C)]
#[cfg_attr(feature = "abi_stable", derive(abi_stable::StableAbi))]
struct FfiWakerVTable {
clone: unsafe extern "C" fn(*const FfiWakerBase) -> *const FfiWakerBase,
wake: unsafe extern "C" fn(*const FfiWakerBase),
wake_by_ref: unsafe extern "C" fn(*const FfiWakerBase),
drop: unsafe extern "C" fn(*const FfiWakerBase),
}

/// The FFI compatible future type with [`Send`] bound.
///
/// See [module level documentation](`crate`) for more details.
#[repr(transparent)]
#[cfg_attr(feature = "abi_stable", derive(abi_stable::StableAbi))]
#[cfg_attr(feature = "stabby", stabby::stabby)]
pub struct BorrowingFfiFuture<'a, T>(LocalBorrowingFfiFuture<'a, T>);

/// The FFI compatible future type with [`Send`] bound and `'static` lifetime,
Expand Down Expand Up @@ -509,6 +520,7 @@ impl<T> Future for BorrowingFfiFuture<'_, T> {
/// See [module level documentation](`crate`) for more details.
#[repr(C)]
#[cfg_attr(feature = "abi_stable", derive(abi_stable::StableAbi))]
#[cfg_attr(feature = "stabby", stabby::stabby)]
pub struct LocalBorrowingFfiFuture<'a, T> {
fut_ptr: *mut (),
poll_fn: unsafe extern "C" fn(fut_ptr: *mut (), context_ptr: *mut FfiContext) -> FfiPoll<T>,
Expand Down