use std::cell::Cell;
use std::rc::Rc;
#[derive(Debug, Default)]
struct AbortState {
aborted: Cell<bool>,
}
#[derive(Debug, Clone)]
pub struct AbortController {
state: Rc<AbortState>,
}
impl AbortController {
pub fn new() -> Self {
Self {
state: Rc::new(AbortState::default()),
}
}
pub fn signal(&self) -> AbortSignal {
AbortSignal {
state: Rc::clone(&self.state),
}
}
pub fn abort(&self) {
self.state.aborted.set(true);
}
pub fn is_aborted(&self) -> bool {
self.state.aborted.get()
}
}
impl Default for AbortController {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
pub struct AbortSignal {
state: Rc<AbortState>,
}
impl AbortSignal {
pub fn is_aborted(&self) -> bool {
self.state.aborted.get()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_controller_not_aborted() {
let c = AbortController::new();
assert!(!c.is_aborted());
assert!(!c.signal().is_aborted());
}
#[test]
fn abort_flips_controller_and_signals() {
let c = AbortController::new();
let s1 = c.signal();
let s2 = c.signal();
c.abort();
assert!(c.is_aborted());
assert!(s1.is_aborted());
assert!(s2.is_aborted());
}
#[test]
fn signal_clone_shares_state() {
let c = AbortController::new();
let s = c.signal();
let s_clone = s.clone();
c.abort();
assert!(s.is_aborted());
assert!(s_clone.is_aborted());
}
#[test]
fn controller_clone_shares_state() {
let c1 = AbortController::new();
let c2 = c1.clone();
let sig = c1.signal();
c2.abort();
assert!(c1.is_aborted());
assert!(c2.is_aborted());
assert!(sig.is_aborted());
}
#[test]
fn default_constructs_unaborted() {
let c: AbortController = Default::default();
assert!(!c.is_aborted());
}
#[test]
fn abort_is_idempotent() {
let c = AbortController::new();
c.abort();
c.abort();
c.abort();
assert!(c.is_aborted());
}
}