| Crates.io | enough-ffi |
| lib.rs | enough-ffi |
| version | 0.3.0 |
| created_at | 2026-01-11 08:49:35.922573+00 |
| updated_at | 2026-01-14 00:24:47.843156+00 |
| description | C FFI helpers for the enough cooperative cancellation trait |
| homepage | |
| repository | https://github.com/imazen/enough |
| max_upload_size | |
| id | 2035432 |
| size | 31,761 |
FFI helpers for the enough cooperative cancellation trait.
This crate provides C-compatible functions and types for bridging cancellation across language boundaries. Use it to integrate Rust libraries with C#/.NET, Python, Node.js, and other languages that can call C APIs.
This crate uses Arc-based reference counting internally to prevent use-after-free:
Arc// Source management
void* enough_cancellation_create(void);
void enough_cancellation_cancel(void* source);
bool enough_cancellation_is_cancelled(void* source);
void enough_cancellation_destroy(void* source);
// Token management
void* enough_token_create(void* source);
void* enough_token_create_never(void);
bool enough_token_is_cancelled(void* token);
void enough_token_destroy(void* token);
When writing Rust FFI functions that receive a token pointer:
use enough_ffi::FfiCancellationToken;
use enough::Stop;
#[no_mangle]
pub extern "C" fn my_operation(
data: *const u8,
len: usize,
token: *const FfiCancellationToken,
) -> i32 {
// Create a non-owning view from the pointer
let stop = unsafe { FfiCancellationToken::from_ptr(token) };
// Use with any library that accepts impl Stop
for i in 0..len {
if i % 100 == 0 && stop.should_stop() {
return -1; // Cancelled
}
// do work...
}
0
}
public class CancellationHandle : IDisposable
{
[DllImport("mylib")] static extern IntPtr enough_cancellation_create();
[DllImport("mylib")] static extern void enough_cancellation_cancel(IntPtr source);
[DllImport("mylib")] static extern void enough_cancellation_destroy(IntPtr source);
[DllImport("mylib")] static extern IntPtr enough_token_create(IntPtr source);
[DllImport("mylib")] static extern void enough_token_destroy(IntPtr token);
private IntPtr _source, _token;
private CancellationTokenRegistration _registration;
public CancellationHandle(CancellationToken ct)
{
_source = enough_cancellation_create();
_token = enough_token_create(_source);
_registration = ct.Register(() => enough_cancellation_cancel(_source));
}
public IntPtr TokenHandle => _token;
public void Dispose()
{
_registration.Dispose();
enough_token_destroy(_token);
enough_cancellation_destroy(_source);
}
}
import ffi from 'ffi-napi';
const lib = ffi.Library('mylib', {
'enough_cancellation_create': ['pointer', []],
'enough_cancellation_cancel': ['void', ['pointer']],
'enough_cancellation_destroy': ['void', ['pointer']],
'enough_token_create': ['pointer', ['pointer']],
'enough_token_destroy': ['void', ['pointer']],
});
function withCancellation(signal, operation) {
const source = lib.enough_cancellation_create();
const token = lib.enough_token_create(source);
const onAbort = () => lib.enough_cancellation_cancel(source);
signal?.addEventListener('abort', onAbort);
try {
return operation(token);
} finally {
signal?.removeEventListener('abort', onAbort);
lib.enough_token_destroy(token);
lib.enough_cancellation_destroy(source);
}
}
| Type | Description |
|---|---|
FfiCancellationSource |
Owns cancellation state, can trigger cancellation |
FfiCancellationToken |
Holds reference to state, can check cancellation |
FfiCancellationTokenView |
Non-owning view for Rust FFI functions |
Licensed under either of Apache License, Version 2.0 or MIT license at your option.