pub struct SyncCompletion<T> { /* private fields */ }Expand description
A synchronous completion handler for async FFI callbacks
This type provides a way to block until an async callback completes
and retrieve the result. It uses Arc<...> internally for thread-safe
signaling between the callback and the waiting thread, with an
AtomicBool guard that defends against Swift firing the completion
callback more than once (which would otherwise be use-after-free in
Arc::from_raw).
Implementations§
Source§impl<T> SyncCompletion<T>
impl<T> SyncCompletion<T>
Sourcepub fn new() -> (Self, SyncCompletionPtr)
pub fn new() -> (Self, SyncCompletionPtr)
Create a new completion handler and return the context pointer for FFI
Returns a tuple of (completion, context_ptr) where:
completionis used to wait for and retrieve the resultcontext_ptrshould be passed to the FFI callback
Sourcepub unsafe fn complete_ok(context: SyncCompletionPtr, value: T)
pub unsafe fn complete_ok(context: SyncCompletionPtr, value: T)
Signal successful completion with a value
§Safety
The context pointer must be a valid pointer obtained from SyncCompletion::new().
This function consumes the Arc reference, so it must only be called once per context.
Sourcepub unsafe fn complete_err(context: SyncCompletionPtr, error: String)
pub unsafe fn complete_err(context: SyncCompletionPtr, error: String)
Signal completion with an error
§Safety
The context pointer must be a valid pointer obtained from SyncCompletion::new().
This function consumes the Arc reference, so it must only be called once per context.
Sourcepub unsafe fn complete_with_result(
context: SyncCompletionPtr,
result: Result<T, String>,
)
pub unsafe fn complete_with_result( context: SyncCompletionPtr, result: Result<T, String>, )
Signal completion with a result
§Safety
The context pointer must be a valid pointer obtained from
SyncCompletion::new() and not yet freed. The intended FFI
contract is that the callback fires exactly once per context.
The consumed AtomicBool provides defence in depth against
Swift firing the callback twice on the same still-live context:
the second invocation atomically observes consumed == true and
returns without touching the Arc, preventing the
double-Arc::from_raw that would otherwise corrupt the refcount.
Limitation: this guard does not protect against the
pathological case where (a) the legitimate callback completed
fully, (b) the corresponding SyncCompletion was dropped (so the
inner allocation was freed), and (c) Swift then fires the
callback a third time with the same now-dangling pointer. The
initial &*context.cast::<...>() deref in that case is
use-after-free. Defending against that scenario would require
either a process-wide allocator (so freed pointers are never
reused) or an indirection through a registry — both beyond the
scope of this guard. Fortunately Apple’s ScreenCaptureKit
callbacks do not exhibit this pattern in practice; this # Safety
note documents the residual contract for future maintainers.
§Panics
Panics if the internal mutex is poisoned.