📡 p3: DoneNotifier — callback-driven async completion (ADR-086)
swadhinbiswas committed 2 months ago
3e6fe90
1 parent 1281187
commit 3e6fe90
1 file changed
+21 -0
Showing 1 changed file+21-0
▼crates/justapi-py/src/native/types.rs
+21-0
| @@ -28,6 +28,27 @@ pub struct StreamSender { | ||
28 | 28 | pub(crate) tx: tokio::sync::mpsc::UnboundedSender<Result<Bytes, anyhow::Error>>, |
29 | 29 | } |
30 | 30 | |
31 | +/// Signals a tokio oneshot when a Python `concurrent.futures.Future` | |
32 | +/// completes. Registered via `future.add_done_callback(notifier)` so the Rust | |
33 | +/// side can `await` completion WITHOUT blocking a thread (no spawn_blocking, | |
34 | +/// no polling). The callback runs on the asyncio loop thread the moment the | |
35 | +/// coroutine finishes. | |
36 | +#[pyclass(name = "_DoneNotifier")] | |
37 | +pub struct DoneNotifier { | |
38 | + pub(crate) tx: std::sync::Mutex<Option<tokio::sync::oneshot::Sender<()>>>, | |
39 | +} | |
40 | + | |
41 | +#[pymethods] | |
42 | +impl DoneNotifier { | |
43 | + fn __call__(&self, _future: Py<PyAny>) { | |
44 | + if let Ok(mut guard) = self.tx.lock() { | |
45 | + if let Some(tx) = guard.take() { | |
46 | + let _ = tx.send(()); | |
47 | + } | |
48 | + } | |
49 | + } | |
50 | +} | |
51 | + | |
31 | 52 | #[pymethods] |
32 | 53 | impl StreamSender { |
33 | 54 | fn send(&self, data: &[u8]) { |
34 | 55 | |