#![allow(dead_code)]
use std::sync::atomic::AtomicBool;
use std::sync::atomic::AtomicIsize;
use std::sync::atomic::Ordering;
use std::sync::Arc;
use std::task::Poll;
use super::atomic_box_option::AtomicBoxOption;
use super::waiters::*;
use futures::future;
use futures::task::Context;
struct ConnOutWindowShared {
window_size: AtomicIsize,
closed: AtomicBool,
}
struct StreamWindowShared {
conn: Arc<ConnOutWindowShared>,
task: AtomicBoxOption<std::task::Waker>,
closed: AtomicBool,
window_size: AtomicIsize,
}
pub struct ConnOutWindowSender {
waker: Waker,
shared: Arc<ConnOutWindowShared>,
}
impl Drop for ConnOutWindowSender {
fn drop(&mut self) {
self.shared.closed.store(true, Ordering::SeqCst);
self.waker.wake_all();
}
}
struct ConnOutWindowReceiver {
shared: Arc<ConnOutWindowShared>,
}
pub struct StreamOutWindowSender {
shared: Arc<StreamWindowShared>,
}
impl Drop for StreamOutWindowSender {
fn drop(&mut self) {
self.shared.closed.store(true, Ordering::SeqCst);
if let Some(task) = self.shared.task.swap_null(Ordering::SeqCst) {
task.wake();
}
}
}
pub struct StreamOutWindowReceiver {
conn_waiter: Waiter,
shared: Arc<StreamWindowShared>,
}
impl ConnOutWindowSender {
pub fn new(size: u32) -> ConnOutWindowSender {
ConnOutWindowSender {
waker: Waker::new(),
shared: Arc::new(ConnOutWindowShared {
window_size: AtomicIsize::new(size as isize),
closed: AtomicBool::new(false),
}),
}
}
pub fn new_stream(&self, initial: u32) -> (StreamOutWindowSender, StreamOutWindowReceiver) {
let shared = Arc::new(StreamWindowShared {
conn: self.shared.clone(),
window_size: AtomicIsize::new(initial as isize),
task: AtomicBoxOption::new(),
closed: AtomicBool::new(false),
});
let sender = StreamOutWindowSender {
shared: shared.clone(),
};
let receiver = StreamOutWindowReceiver {
conn_waiter: self.waker.new_waiter(),
shared: shared,
};
(sender, receiver)
}
pub fn get(&self) -> isize {
self.shared.window_size.load(Ordering::SeqCst) as isize
}
pub fn increase(&self, size: usize) {
assert!(size <= isize::max_value() as usize);
let old_size = self
.shared
.window_size
.fetch_add(size as isize, Ordering::SeqCst);
let new_size = old_size + size as isize;
if new_size > 0 {
self.waker.wake_all();
}
}
}
impl StreamOutWindowSender {
pub fn increase(&self, size: isize) {
let old_size = self
.shared
.window_size
.fetch_add(size as isize, Ordering::SeqCst);
let new_size = old_size + size as isize;
if new_size > 0 {
if let Some(task) = self.shared.task.swap_null(Ordering::SeqCst) {
task.wake();
}
}
}
pub fn get(&self) -> isize {
self.shared.window_size.load(Ordering::SeqCst) as isize
}
}
struct ConnDead;
#[derive(Eq, PartialEq, Debug)]
pub enum StreamDead {
Stream,
Conn,
}
impl From<ConnDead> for StreamDead {
fn from(_: ConnDead) -> StreamDead {
StreamDead::Conn
}
}
impl StreamOutWindowReceiver {
pub fn decrease(&self, size: usize) {
self.shared
.conn
.window_size
.fetch_sub(size as isize, Ordering::SeqCst);
self.shared
.window_size
.fetch_sub(size as isize, Ordering::SeqCst);
}
fn check_conn_closed(&self) -> Result<(), ConnDead> {
if self.shared.conn.closed.load(Ordering::Relaxed) {
Err(ConnDead)
} else {
Ok(())
}
}
fn check_stream_closed(&self) -> Result<(), StreamDead> {
self.check_conn_closed()?;
if self.shared.closed.load(Ordering::SeqCst) {
Err(StreamDead::Stream)
} else {
Ok(())
}
}
fn poll_conn(&self, cx: &mut Context<'_>) -> Poll<Result<(), ConnDead>> {
self.check_conn_closed()?;
if self.shared.conn.window_size.load(Ordering::SeqCst) > 0 {
return Poll::Ready(Ok(()));
}
self.conn_waiter.park(cx);
self.check_conn_closed()?;
if self.shared.conn.window_size.load(Ordering::SeqCst) > 0 {
Poll::Ready(Ok(()))
} else {
Poll::Pending
}
}
pub fn poll(&self, cx: &mut Context<'_>) -> Poll<Result<(), StreamDead>> {
self.check_stream_closed()?;
if self.shared.window_size.load(Ordering::SeqCst) <= 0 {
self.shared
.task
.store_box(Box::new(cx.waker().clone()), Ordering::SeqCst);
self.check_stream_closed()?;
if self.shared.window_size.load(Ordering::SeqCst) <= 0 {
return Poll::Pending;
}
}
self.poll_conn(cx).map_err(|e| e.into())
}
pub async fn poll_f(&self) -> Result<(), StreamDead> {
future::poll_fn(|cx| self.poll(cx)).await
}
}