transcribe_cpp/cancel.rs
1//! Cooperative cancellation for in-flight runs and streams.
2//!
3//! A [`CancelToken`] wraps a shared atomic flag. Install it on a session, then
4//! call [`CancelToken::cancel`] from any thread to abort the in-flight
5//! `run`/`feed`/`finalize`: the native abort callback (polled between decode
6//! steps) sees the flag and stops, the call returns [`crate::Error::Aborted`]
7//! with the partial transcript, and [`crate::Session::was_aborted`] reports
8//! true.
9
10use std::os::raw::c_void;
11use std::sync::atomic::{AtomicBool, Ordering};
12use std::sync::Arc;
13
14/// A clonable cancellation handle. Clones share one underlying flag, so a
15/// worker thread can hold a clone and cancel a run executing on another thread.
16#[derive(Debug, Clone, Default)]
17pub struct CancelToken {
18 pub(crate) flag: Arc<AtomicBool>,
19}
20
21impl CancelToken {
22 /// A fresh, un-cancelled token.
23 pub fn new() -> Self {
24 CancelToken::default()
25 }
26
27 /// Request cancellation of the run/stream this token is installed on.
28 pub fn cancel(&self) {
29 self.flag.store(true, Ordering::SeqCst);
30 }
31
32 /// Whether cancellation has been requested.
33 pub fn is_cancelled(&self) -> bool {
34 self.flag.load(Ordering::SeqCst)
35 }
36
37 /// Clear the cancelled state so the token can be reused for another run.
38 pub fn reset(&self) {
39 self.flag.store(false, Ordering::SeqCst);
40 }
41}
42
43/// The C abort callback. `userdata` is an `Arc<AtomicBool>`'s pointee, kept
44/// alive by the session for the duration of any run. Invoked on the run thread
45/// (the C library polls it between decode steps), so it must be cheap and
46/// thread-safe — an atomic load is both.
47pub(crate) extern "C" fn abort_trampoline(userdata: *mut c_void) -> bool {
48 if userdata.is_null() {
49 return false;
50 }
51 // SAFETY: `userdata` is the `*const AtomicBool` the session installed and
52 // keeps alive (via a retained Arc) for as long as the callback is set.
53 let flag = unsafe { &*(userdata as *const AtomicBool) };
54 flag.load(Ordering::SeqCst)
55}