Skip to main content

appcore_transfer/
control.rs

1// =============================================================================
2//        #######
3//     ###       ###     F: control.rs
4//    ##   ## ##   ##    P: AppCore-Runtime
5//         ## ##
6//                       C: 2026/10/06 00:00:00 by dnettoRaw
7//    ##   ## ##   ##    U: 2026/10/06 00:00:00 by dnettoRaw
8//      ###########      S: 0.1.0-beta.1
9// =============================================================================
10
11//! Cooperative cancellation with a checked monotonic deadline.
12use crate::{TransferError as E, TransferResult};
13use std::sync::{
14    atomic::{AtomicBool, Ordering},
15    Arc,
16};
17use std::time::{Duration, Instant};
18/// Shared cancellation/deadline for all bounded workers; never starts background tasks.
19#[derive(Debug, Clone)]
20pub struct TransferControl {
21    cancelled: Arc<AtomicBool>,
22    deadline: Instant,
23}
24impl TransferControl {
25    /// Creates a deadline between 1 ms and 24 hours.
26    pub fn new(timeout: Duration) -> TransferResult<Self> {
27        if timeout < Duration::from_millis(1) || timeout > Duration::from_secs(86400) {
28            return Err(E::InvalidContract);
29        }
30        Ok(Self {
31            cancelled: Arc::new(AtomicBool::new(false)),
32            deadline: Instant::now()
33                .checked_add(timeout)
34                .ok_or(E::InvalidContract)?,
35        })
36    }
37    /// Requests cooperative cancellation; providers must return within their I/O bounds.
38    pub fn cancel(&self) {
39        self.cancelled.store(true, Ordering::Release);
40    }
41    /// Returns a typed cancellation/deadline failure.
42    pub fn checkpoint(&self) -> TransferResult<()> {
43        if self.cancelled.load(Ordering::Acquire) {
44            return Err(E::Cancelled);
45        }
46        if Instant::now() >= self.deadline {
47            return Err(E::Deadline);
48        }
49        Ok(())
50    }
51    /// Remaining monotonic deadline, for deployment-owned transport timeouts.
52    pub fn remaining(&self) -> Duration {
53        self.deadline.saturating_duration_since(Instant::now())
54    }
55    pub(crate) fn wait(&self, delay: Duration) -> TransferResult<()> {
56        let until = Instant::now()
57            .checked_add(delay)
58            .ok_or(E::InvalidContract)?;
59        while Instant::now() < until {
60            self.checkpoint()?;
61            std::thread::sleep(
62                until
63                    .saturating_duration_since(Instant::now())
64                    .min(Duration::from_millis(10)),
65            );
66        }
67        self.checkpoint()
68    }
69}