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
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
//!
//! FFI support for [`future_form`]: host-driven polling, opaque handles,
//! and effect slots.
//!
//! This crate provides the building blocks for FFI bridges that let
//! foreign hosts (Go, Java, Python, C, Swift) drive Rust async state
//! machines without an async runtime.
//!
//! # Core types
//!
//! | Type | Purpose |
//! |------|---------|
//! | [`PollOnce`](poll_once::PollOnce) | Extension trait: poll a boxed future once with a no-op waker |
//! | [`HostHandle`](host_handle::HostHandle) | Thin-pointer wrapper for passing boxed futures through C ABI |
//! | [`AtomicSlot`](atomic_slot::AtomicSlot) | Lock-free, thread-safe slot for a single value |
//! | [`EffectSlot`](effect_slot::EffectSlot) | Shared-state channel for the effect protocol (built on `AtomicSlot`) |
//! | [`EffectHandle`](effect_handle::EffectHandle) | Future handle + stashed effect + context pointer |
//!
//! # Architecture
//!
//! ```text
//! ┌────────────┐ ┌──────────────────────┐
//! │ FFI Host │ poll_once() │ HostHandle<F> │
//! │ (Go, Java │ ──────────────────>│ or EffectHandle │
//! │ Python…) │ <──────────────────│ │
//! │ │ Poll<T> │ │
//! │ │ │ ┌────────────────┐ │
//! │ │ take_effect() │ │ EffectSlot │ │
//! │ │ ──────────────────>│ │ <E, R> │ │
//! │ │ <──────────────────│ └────────────────┘ │
//! │ │ fulfill(resp) │ │
//! │ │ ──────────────────>│ │
//! └────────────┘ └──────────────────────┘
//! ```
//!
//! # FFI bridge pattern
//!
//! FFI hosts can't receive a Rust `Box<T>` directly — they need a raw
//! pointer. The standard pattern is:
//!
//! 1. **Create**: heap-allocate the handle and convert to a raw pointer
//! with [`Box::into_raw`](alloc::boxed::Box::into_raw), transferring ownership to the host.
//! 2. **Poll/inspect**: the host passes the pointer back into Rust
//! bridge functions that reconstruct a reference (`&mut *ptr`).
//! 3. **Free**: the host calls a destructor that reclaims ownership
//! with [`Box::from_raw`](alloc::boxed::Box::from_raw) and drops the handle.
//!
//! ```rust,ignore
//! // 1. Create — ownership moves to the host
//! let handle = HostHandle::new(fut);
//! let ptr = Box::into_raw(Box::new(handle)); // thin *mut for C ABI
//!
//! // 2. Poll — borrow from the raw pointer
//! let handle = unsafe { &mut *ptr };
//! let result = handle.poll_once();
//!
//! // 3. Free — reclaim and drop
//! unsafe { drop(Box::from_raw(ptr)) };
//! ```
//!
//! [`EffectHandle`](effect_handle::EffectHandle) follows the same
//! pattern, adding a stashed effect and context pointer for the effect
//! protocol.
//!
//! # Example
//!
//! Simple bridge using [`HostHandle`](host_handle::HostHandle):
//!
//! ```rust
//! use core::task::Poll;
//! use future_form::{FutureForm, Sendable};
//! use future_form_ffi::host_handle::HostHandle;
//!
//! let fut = Sendable::from_future(async { 42u64 });
//! let mut handle = HostHandle::new(fut);
//! assert_eq!(handle.poll_once(), Poll::Ready(42));
//! ```
//!
//! Effect protocol using [`EffectSlot`](effect_slot::EffectSlot):
//!
//! ```rust
//! use core::task::Poll;
//! use future_form_ffi::effect_slot::EffectSlot;
//!
//! #[derive(Clone, Debug, PartialEq)]
//! enum Fx { GetTime }
//!
//! #[derive(Debug, PartialEq)]
//! enum Resp { Time(u64) }
//!
//! let slot: EffectSlot<Fx, Resp> = EffectSlot::new();
//! assert_eq!(slot.request(&Fx::GetTime), Poll::Pending);
//! slot.fulfill(Resp::Time(1234));
//! assert_eq!(slot.request(&Fx::GetTime), Poll::Ready(Resp::Time(1234)));
//! ```
//!
//! # Slot ownership
//!
//! An [`EffectSlot`](effect_slot::EffectSlot) is a single
//! request-response channel. If multiple futures share the same slot,
//! they will overwrite each other's pending effects and receive
//! responses intended for other futures. This is memory-safe (all
//! operations are atomic) but semantically incorrect.
//!
//! Two ownership strategies are supported:
//!
//! ## Per-struct slot (simple, one future at a time)
//!
//! Embed the slot in the struct. All futures share it. Only one future
//! may be in flight at a time:
//!
//! ```rust,ignore
//! struct MyService {
//! state: u64,
//! effects: EffectSlot<Effect, Response>,
//! }
//! ```
//!
//! ## Per-future `Arc<EffectSlot>` (unlimited concurrent futures)
//!
//! Create a fresh slot for each future. Share it via `Arc` between the
//! async closure and the [`EffectHandle`](effect_handle::EffectHandle).
//! There is no limit on the number of in-flight futures — each one gets
//! its own independent effect channel:
//!
//! ```rust,ignore
//! use alloc::sync::Arc;
//!
//! let slot = Arc::new(EffectSlot::new());
//! let slot_for_future = Arc::clone(&slot);
//!
//! let fut = Box::pin(async move {
//! let resp = core::future::poll_fn(|_cx| {
//! slot_for_future.request(&Effect::GetTimestamp)
//! }).await;
//! // ...
//! });
//!
//! let handle = EffectHandle::new(HostHandle::new(fut), context);
//! // The bridge stores `slot` alongside the handle (e.g., in a wrapper struct)
//! // so the host can call slot.take_effect() / slot.fulfill().
//! ```
//!
//! The per-future approach has no capacity limit — the host can create
//! as many concurrent futures as memory allows, each with its own
//! effect channel. The cost is one `Arc` allocation per future,
//! negligible alongside the `Box::pin` that already heap-allocates the
//! future. The [`key_value_store`] example demonstrates this pattern
//! with concurrent Get/Put/Delete/List operations. See the [design docs]
//! for a full comparison of ownership strategies including slot
//! registries and fixed-size arrays.
//!
//! [`key_value_store`]: https://codeberg.org/expede/future_form/src/branch/main/future_form_ffi/examples/key_value_store/
//!
//! [design docs]: https://codeberg.org/expede/future_form/src/branch/main/design/host-driven-ffi.md#effect-slot-ownership
//!
//! # Handle storage
//!
//! Rust does not assign or manage future IDs. The
//! [`EffectHandle`](effect_handle::EffectHandle) _is_ the identity —
//! an opaque token bundling the future, its slot, and its context. The
//! host stores these however its concurrency model demands:
//!
//! ## Host-side collection
//!
//! The host keeps a map of handles, keyed however it likes:
//!
//! ```text
//! Host (Go / Java / Python)
//! ┌─────────────────────────────────────────────┐
//! │ │
//! │ handles: Map<FutureId, *mut EffectHandle> │
//! │ │
//! │ handle_1 ──► EffectHandle ──► Arc<slot_1> │
//! │ handle_2 ──► EffectHandle ──► Arc<slot_2> │
//! │ handle_3 ──► EffectHandle ──► Arc<slot_3> │
//! │ │
//! └─────────────────────────────────────────────┘
//! ```
//!
//! The `FutureId` is whatever the host wants — an integer counter, a
//! UUID, a task name. It is entirely host-side bookkeeping. Rust does
//! not know or care about it.
//!
//! ## Inline in host tasks
//!
//! Each host-side task/goroutine/thread holds its handle directly — no
//! map needed:
//!
//! ```text
//! Go goroutine A Go goroutine B
//! ┌──────────────────┐ ┌──────────────────┐
//! │ handle *C.Handle │ │ handle *C.Handle │
//! └────────┬─────────┘ └────────┬─────────┘
//! │ │
//! ▼ ▼
//! EffectHandle EffectHandle
//! └─► Arc<slot_a> └─► Arc<slot_b>
//! ```
//!
//! No future ID at all — the handle _is_ the identity.
//!
//! ## Event loop with a vec
//!
//! ```text
//! Host event loop
//! ┌──────────────────────────────┐
//! │ active: Vec<EffectHandle> │
//! │ │
//! │ for handle in &mut active { │
//! │ match handle.poll() { │
//! │ Pending => check fx │
//! │ Ready => remove │
//! │ } │
//! │ } │
//! └──────────────────────────────┘
//! ```
//!
//! The index in the vec is the implicit ID, or the host uses a slab
//! allocator. When a future completes, the host removes it — the
//! handle drops, its `Arc<EffectSlot>` drops, and the slot is freed.
//!
//! All three patterns work because `EffectHandle` is self-contained:
//! the host never needs to coordinate with Rust about which handle
//! maps to which future. See the [design docs] for more detail.
//!
//! # `no_std` support
//!
//! This crate is `#![no_std]` and requires only `core` + `alloc`. No
//! feature flags, no platform-specific dependencies.
//!
//! [`EffectSlot`](effect_slot::EffectSlot) is built on
//! [`AtomicSlot`](atomic_slot::AtomicSlot), which uses lock-free
//! [`AtomicPtr`](core::sync::atomic::AtomicPtr) swaps for thread
//! safety — no mutex, no poisoning, no global lock contention.
extern crate alloc;