use std::{
fmt::{Debug, Formatter, Result},
future::{Future, IntoFuture},
pin::Pin,
sync::{
atomic::{AtomicBool, Ordering},
Arc,
},
task::{Context, Poll},
};
use trillium::Info;
use trillium_http::Stopper;
#[derive(Clone, Debug)]
pub struct ServerHandle {
pub(crate) stopper: Stopper,
pub(crate) info: Arc<async_cell::sync::AsyncCell<Info>>,
pub(crate) completion: CompletionFuture,
}
#[derive(Clone, Default)]
pub struct CompletionFuture(Arc<CompletionFutureInner>);
impl CompletionFuture {
pub(crate) fn notify(self) {
if !self.0.complete.swap(true, Ordering::SeqCst) {
self.0.waker_set.notify_all();
}
}
pub(crate) fn is_complete(&self) -> bool {
self.0.complete.load(Ordering::SeqCst)
}
pub(crate) fn new() -> Self {
Self::default()
}
}
pub struct CompletionFutureInner {
complete: AtomicBool,
waker_set: waker_set::WakerSet,
}
impl Default for CompletionFutureInner {
fn default() -> Self {
Self {
complete: AtomicBool::new(false),
waker_set: waker_set::WakerSet::new(),
}
}
}
impl Debug for CompletionFuture {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
f.debug_tuple("CompletionFuture")
.field(&self.0.complete)
.finish()
}
}
impl Future for CompletionFuture {
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if self.0.complete.load(Ordering::SeqCst) {
Poll::Ready(())
} else {
let key = self.0.waker_set.insert(cx);
if self.0.complete.load(Ordering::SeqCst) {
self.0.waker_set.cancel(key);
Poll::Ready(())
} else {
Poll::Pending
}
}
}
}
impl ServerHandle {
pub async fn info(&self) -> Info {
self.info.get().await
}
pub async fn stop(&self) {
self.stopper.stop();
self.completion.clone().await
}
pub fn stopper(&self) -> Stopper {
self.stopper.clone()
}
pub fn is_running(&self) -> bool {
!self.completion.is_complete()
}
}
impl IntoFuture for ServerHandle {
type Output = ();
type IntoFuture = CompletionFuture;
fn into_future(self) -> Self::IntoFuture {
self.completion
}
}