#![allow(dead_code)]
use std::{
fmt::{self, Debug},
hash::Hash,
io,
mem::{self, ManuallyDrop},
ops::{Deref, DerefMut},
ptr,
task::Waker,
};
use compio_buf::{BufResult, IntoInner};
use compio_send_wrapper::SendWrapper;
use thin_cell::unsync::{Inner, Ref, ThinCell, Weak};
use crate::{Carry, DriverType, Extra, OpCode, PushEntry, control::Carrier};
#[repr(C)]
pub(crate) struct RawOp<M: ?Sized> {
extra: Extra,
cancelled: bool,
result: PushEntry<Option<Waker>, io::Result<usize>>,
pub(crate) carrier: M,
}
impl<C: ?Sized> RawOp<C> {
pub fn extra(&self) -> &Extra {
&self.extra
}
pub fn extra_mut(&mut self) -> &mut Extra {
&mut self.extra
}
#[cfg(io_uring)]
pub fn wake_by_ref(&mut self) {
if let PushEntry::Pending(Some(w)) = &self.result {
w.wake_by_ref();
}
}
}
#[cfg(io_uring)]
impl<C: crate::Carry + ?Sized> RawOp<C> {
pub fn create_entry<const FALLBACK: bool>(&mut self) -> crate::OpEntry {
if FALLBACK {
self.carrier.create_entry_fallback().with_extra(&self.extra)
} else {
self.carrier.create_entry().with_extra(&self.extra)
}
}
}
#[cfg(windows)]
impl<C: crate::Carry + ?Sized> RawOp<C> {
pub fn operate_blocking(&mut self) -> io::Result<usize> {
use std::{panic::AssertUnwindSafe, task::Poll};
use crate::panic::catch_unwind_io;
let optr = self.extra_mut().optr();
catch_unwind_io(AssertUnwindSafe(|| unsafe {
match self.carrier.operate(optr.cast()) {
Poll::Pending => unreachable!("this operation is not overlapped"),
Poll::Ready(res) => res,
}
}))
}
}
impl<C: ?Sized> Debug for RawOp<C> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("RawOp")
.field("extra", &self.extra)
.field("cancelled", &self.cancelled)
.field("result", &self.result)
.field("Carrier", &"<...>")
.finish()
}
}
#[repr(transparent)]
pub struct Key<T> {
erased: ErasedKey,
_p: std::marker::PhantomData<T>,
}
#[derive(Clone)]
#[repr(transparent)]
pub struct ErasedKey {
inner: ThinCell<RawOp<dyn Carry>>,
}
#[derive(Clone)]
#[repr(transparent)]
pub(crate) struct WeakKey {
inner: Weak<RawOp<dyn Carry>>,
}
impl<T> Clone for Key<T> {
fn clone(&self) -> Self {
Self {
erased: self.erased.clone(),
_p: std::marker::PhantomData,
}
}
}
impl<T> Debug for Key<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Key({})", self.erased.inner.as_ptr() as usize)
}
}
impl<T> Key<T> {
pub(crate) fn into_raw(self) -> usize {
self.erased.into_raw()
}
pub(crate) fn erase(self) -> ErasedKey {
self.erased
}
}
impl<T: OpCode> Key<T> {
pub(crate) fn take_result(self) -> BufResult<usize, T> {
unsafe { self.erased.take_result::<T>() }
}
}
impl<T: OpCode + 'static> Key<T> {
pub(crate) fn new(op: T, extra: impl Into<Extra>, driver_ty: DriverType) -> Self {
let erased = ErasedKey::new(op, extra.into(), driver_ty);
Self {
erased,
_p: std::marker::PhantomData,
}
}
pub(crate) fn set_extra(&self, extra: impl Into<Extra>) {
self.borrow().extra = extra.into();
}
}
impl<T> Deref for Key<T> {
type Target = ErasedKey;
fn deref(&self) -> &Self::Target {
&self.erased
}
}
impl<T> DerefMut for Key<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.erased
}
}
impl PartialEq for ErasedKey {
fn eq(&self, other: &Self) -> bool {
self.inner.ptr_eq(&other.inner)
}
}
impl Eq for ErasedKey {}
impl Hash for ErasedKey {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
(self.inner.as_ptr() as usize).hash(state)
}
}
impl Unpin for ErasedKey {}
impl ErasedKey {
pub(crate) fn new<T: OpCode + 'static>(op: T, extra: Extra, driver_ty: DriverType) -> Self {
let raw_op = RawOp {
extra,
cancelled: false,
result: PushEntry::Pending(None),
carrier: Carrier::new(op, driver_ty),
};
let mut inner = ThinCell::new(raw_op);
unsafe { inner.borrow_unchecked().carrier.init() };
Self {
inner: unsafe { inner.unsize(|p| p as *const Inner<RawOp<dyn Carry>>) },
}
}
pub(crate) unsafe fn from_raw(user_data: usize) -> Self {
let inner = unsafe { ThinCell::from_raw(user_data as *mut ()) };
Self { inner }
}
#[cfg(windows)]
pub(crate) unsafe fn from_optr(optr: *mut crate::sys::Overlapped) -> Self {
let ptr = unsafe { optr.cast::<usize>().offset(-2).cast() };
let inner = unsafe { ThinCell::from_raw(ptr) };
Self { inner }
}
#[cfg(windows)]
pub(crate) fn into_optr(self) -> *mut crate::sys::Overlapped {
unsafe { self.inner.leak().cast::<usize>().add(2).cast() }
}
pub(crate) fn downgrade(&self) -> WeakKey {
WeakKey {
inner: self.inner.downgrade(),
}
}
pub(crate) fn as_raw(&self) -> usize {
self.inner.as_ptr() as _
}
pub(crate) fn into_raw(self) -> usize {
self.inner.leak() as _
}
#[inline]
pub(crate) fn borrow(&self) -> Ref<'_, RawOp<dyn Carry>> {
self.inner.borrow()
}
pub(crate) fn set_cancelled(&self) -> bool {
let mut op = self.borrow();
mem::replace(&mut op.cancelled, true)
}
pub(crate) fn has_result(&self) -> bool {
self.borrow().result.is_ready()
}
pub(crate) fn is_unique(&self) -> bool {
ThinCell::count(&self.inner) == 1
}
pub(crate) fn set_result(&self, res: io::Result<usize>) {
let mut this = self.borrow();
{
let RawOp { extra, carrier, .. } = &mut *this;
unsafe { crate::sys::Carry::set_result(carrier, &res, extra) };
}
if let PushEntry::Pending(Some(w)) =
std::mem::replace(&mut this.result, PushEntry::Ready(res))
{
w.wake();
}
}
pub(crate) fn swap_extra(&self, extra: Extra) -> Extra {
std::mem::replace(&mut self.borrow().extra, extra)
}
pub(crate) fn set_waker(&self, waker: &Waker) {
let PushEntry::Pending(w) = &mut self.borrow().result else {
return;
};
if w.as_ref().is_some_and(|w| w.will_wake(waker)) {
return;
}
*w = Some(waker.clone());
}
unsafe fn take_result<T: OpCode>(self) -> BufResult<usize, T> {
let this = unsafe { self.inner.downcast_unchecked::<RawOp<Carrier<T>>>() };
let op = this.try_unwrap().map_err(|_| ()).expect("Key not unique");
let res = op.result.take_ready().expect("Result not ready");
BufResult(res, op.carrier.into_inner())
}
pub(crate) unsafe fn freeze(self) -> FrozenKey {
FrozenKey {
inner: ManuallyDrop::new(self),
thread_id: SendWrapper::new(()),
}
}
}
impl Debug for ErasedKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "ErasedKey({})", self.inner.as_ptr() as usize)
}
}
impl WeakKey {
pub(crate) fn upgrade(&self) -> Option<ErasedKey> {
Some(ErasedKey {
inner: self.inner.upgrade()?,
})
}
pub(crate) fn as_ptr(&self) -> *const () {
self.inner.as_ptr()
}
}
impl PartialEq for WeakKey {
fn eq(&self, other: &Self) -> bool {
ptr::eq(self.inner.as_ptr(), other.inner.as_ptr())
}
}
impl Eq for WeakKey {}
impl Hash for WeakKey {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
(self.inner.as_ptr() as usize).hash(state)
}
}
impl Debug for WeakKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(upgraded) = self.inner.upgrade() {
Debug::fmt(&upgraded, f)
} else {
write!(f, "(Dropped)")
}
}
}
#[repr(C)]
pub(crate) struct FrozenKey {
inner: ManuallyDrop<ErasedKey>,
thread_id: SendWrapper<()>,
}
impl FrozenKey {
pub fn as_mut(&mut self) -> &mut RawOp<dyn Carry> {
unsafe { self.inner.inner.borrow_unchecked() }
}
pub fn into_inner(self) -> ErasedKey {
let mut this = ManuallyDrop::new(self);
unsafe { ManuallyDrop::take(&mut this.inner) }
}
}
impl Drop for FrozenKey {
fn drop(&mut self) {
if self.thread_id.valid() {
unsafe { ManuallyDrop::drop(&mut self.inner) }
}
}
}
unsafe impl Send for FrozenKey {}
unsafe impl Sync for FrozenKey {}
pub(crate) struct BorrowedKey(ManuallyDrop<ErasedKey>);
impl BorrowedKey {
pub unsafe fn from_raw(user_data: usize) -> Self {
let key = unsafe { ErasedKey::from_raw(user_data) };
Self(ManuallyDrop::new(key))
}
pub fn upgrade(self) -> ErasedKey {
ManuallyDrop::into_inner(self.0)
}
}
impl Deref for BorrowedKey {
type Target = ErasedKey;
fn deref(&self) -> &Self::Target {
&self.0
}
}