#![forbid(unsafe_code, future_incompatible)]
#![deny(
missing_debug_implementations,
nonstandard_style,
missing_copy_implementations,
unused_qualifications,
missing_docs,
rustdoc::missing_crate_level_docs
)]
#![warn(clippy::pedantic)]
use std::{future::IntoFuture, sync::Arc};
mod implementation;
use implementation::Inner;
pub use implementation::{Guard, Guarded, Interrupt, ShutdownCompletion, ShuttingDown};
#[derive(Debug)]
pub struct Swansong {
inner: Arc<Inner>,
}
impl Clone for Swansong {
fn clone(&self) -> Self {
self.inner.swansong_clone();
Self {
inner: Arc::clone(&self.inner),
}
}
}
impl Default for Swansong {
fn default() -> Self {
Self::new()
}
}
impl Eq for Swansong {}
impl PartialEq for Swansong {
fn eq(&self, other: &Self) -> bool {
Arc::ptr_eq(&self.inner, &other.inner)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ShutdownState {
Running,
ShuttingDown,
Complete,
}
impl ShutdownState {
#[must_use]
pub fn is_running(&self) -> bool {
matches!(self, ShutdownState::Running)
}
#[must_use]
pub fn is_shutting_down(&self) -> bool {
matches!(self, ShutdownState::ShuttingDown)
}
#[must_use]
pub fn is_complete(&self) -> bool {
matches!(self, ShutdownState::Complete)
}
}
impl Swansong {
#[must_use]
pub fn new() -> Self {
Self {
inner: Inner::new_root(),
}
}
#[allow(clippy::must_use_candidate)] pub fn shut_down(&self) -> ShutdownCompletion {
self.inner.stop();
ShutdownCompletion::new(&self.inner)
}
pub fn block_on_shutdown_completion(self) {
ShutdownCompletion::new(&self.inner).block();
}
#[must_use]
pub fn state(&self) -> ShutdownState {
let stopped = self.inner.is_stopped();
let complete = stopped && self.inner.is_zero();
if complete {
ShutdownState::Complete
} else if stopped {
ShutdownState::ShuttingDown
} else {
ShutdownState::Running
}
}
#[must_use]
pub fn shutting_down(&self) -> ShuttingDown {
ShuttingDown::new(&self.inner)
}
#[must_use]
pub fn interrupt<T>(&self, wrapped_type: T) -> Interrupt<T> {
Interrupt::new(&self.inner, wrapped_type)
}
#[must_use]
pub fn guard(&self) -> Guard {
Guard::new(&self.inner)
}
#[must_use]
pub fn guard_count(&self) -> usize {
self.inner.guard_count_subtree()
}
#[must_use]
pub fn child(&self) -> Swansong {
Swansong {
inner: Inner::new_child(&self.inner),
}
}
#[must_use]
pub fn guarded<T>(&self, wrapped_type: T) -> Guarded<T> {
Guarded::new(&self.inner, wrapped_type)
}
}
impl Drop for Swansong {
fn drop(&mut self) {
if self.inner.swansong_drop() && self.inner.is_root() {
self.inner.stop();
}
}
}
impl IntoFuture for Swansong {
type Output = ();
type IntoFuture = ShutdownCompletion;
fn into_future(self) -> Self::IntoFuture {
ShutdownCompletion::new(&self.inner)
}
}