use core::ptr;
use core::sync::atomic::{AtomicPtr, Ordering};
use core::task::{Poll, Waker};
use std::io;
use super::work::{Counted, Work, counted, tally_write};
use crate::buf::owned::OwnedBuf;
pub(super) enum Orphan {
Pool(Work<io::Result<()>>, Counted),
Lent(Work<(io::Result<()>, OwnedBuf)>, Counted),
Count(Work<io::Result<u64>>),
}
impl From<(Work<io::Result<()>>, Counted)> for Orphan {
fn from((work, bytes): (Work<io::Result<()>>, Counted)) -> Self {
Orphan::Pool(work, bytes)
}
}
impl From<(Work<(io::Result<()>, OwnedBuf)>, Counted)> for Orphan {
fn from((work, bytes): (Work<(io::Result<()>, OwnedBuf)>, Counted)) -> Self {
Orphan::Lent(work, bytes)
}
}
impl From<(Work<io::Result<u64>>, Counted)> for Orphan {
fn from((work, _): (Work<io::Result<u64>>, Counted)) -> Self {
Orphan::Count(work)
}
}
impl Orphan {
pub(super) fn poll(&mut self, waker: &Waker) -> Poll<Option<io::Error>> {
let (err, bytes) = match self {
Orphan::Pool(work, bytes) => (core::task::ready!(work.poll(waker)).err(), *bytes),
Orphan::Lent(work, bytes) => (core::task::ready!(work.poll(waker)).0.err(), *bytes),
Orphan::Count(work) => (core::task::ready!(work.poll(waker)).err(), counted(0)),
};
tally_write(bytes, err.is_none());
Poll::Ready(err)
}
pub(super) fn let_go(self) {
match self {
Orphan::Pool(work, _) => work.let_go(),
Orphan::Lent(work, _) => work.let_go(),
Orphan::Count(work) => work.let_go(),
}
}
}
struct Node {
orphan: Orphan,
next: *mut Node,
}
pub(super) struct Orphans {
head: AtomicPtr<Node>,
}
unsafe impl Send for Orphans {}
unsafe impl Sync for Orphans {}
impl Orphans {
pub(super) const fn new() -> Self {
Self {
head: AtomicPtr::new(ptr::null_mut()),
}
}
pub(super) fn push(&self, orphan: Orphan) {
let node = Box::into_raw(Box::new(Node {
orphan,
next: ptr::null_mut(),
}));
let mut head = self.head.load(Ordering::Relaxed);
loop {
unsafe { (*node).next = head };
match self
.head
.compare_exchange_weak(head, node, Ordering::Release, Ordering::Relaxed)
{
Ok(_) => return,
Err(now) => head = now,
}
}
}
pub(super) fn take(&self, into: &mut Vec<Orphan>) {
if self.head.load(Ordering::Relaxed).is_null() {
return;
}
let mut node = self.head.swap(ptr::null_mut(), Ordering::Acquire);
while !node.is_null() {
let taken = unsafe { Box::from_raw(node) };
node = taken.next;
into.push(taken.orphan);
}
}
}
impl Drop for Orphans {
fn drop(&mut self) {
let mut left = Vec::new();
self.take(&mut left);
for orphan in left {
orphan.let_go();
}
}
}