use super::{
free_list::FreeList,
probes,
queue::{Half, Queue},
};
use crate::sync::ring_deque;
use s2n_quic_core::{ensure, varint::VarInt};
use std::{
cell::UnsafeCell,
marker::PhantomData,
ptr::NonNull,
sync::{
atomic::{AtomicUsize, Ordering},
Arc,
},
};
pub(super) struct Descriptor<T, Key> {
ptr: NonNull<DescriptorInner<T, Key>>,
phantom: PhantomData<DescriptorInner<T, Key>>,
}
impl<T: 'static, Key: 'static> Descriptor<T, Key> {
#[inline]
pub(super) fn new(ptr: NonNull<DescriptorInner<T, Key>>) -> Self {
Self {
ptr,
phantom: PhantomData,
}
}
#[inline]
pub unsafe fn clone_for_sender(&self) -> Descriptor<T, Key> {
self.inner().senders.fetch_add(1, Ordering::Relaxed);
Descriptor::new(self.ptr)
}
#[inline]
pub unsafe fn drop_in_place(&self) {
core::ptr::drop_in_place(self.ptr.as_ptr());
}
#[cfg(debug_assertions)]
pub(super) fn as_usize(&self) -> usize {
self.ptr.as_ptr() as usize
}
#[inline]
pub unsafe fn queue_id(&self) -> VarInt {
self.inner().id
}
#[inline]
pub unsafe fn stream_queue(&self) -> &Queue<T> {
&self.inner().stream
}
#[inline]
pub unsafe fn control_queue(&self) -> &Queue<T> {
&self.inner().control
}
pub unsafe fn take_key(&mut self) -> Option<Key> {
core::ptr::replace(self.inner().key.get(), None)
}
#[inline]
fn inner(&self) -> &DescriptorInner<T, Key> {
unsafe { self.ptr.as_ref() }
}
#[inline]
pub unsafe fn into_receiver_pair(self, key: Option<Key>) -> (Self, Self) {
let inner = self.inner();
inner.stream.open_receivers(&inner.control).unwrap();
let _ = core::ptr::replace(inner.key.get(), key);
probes::on_receiver_open(inner.id);
let other = Self {
ptr: self.ptr,
phantom: PhantomData,
};
(self, other)
}
#[inline]
pub unsafe fn drop_sender(&self) {
let inner = self.inner();
let desc_ref = inner.senders.fetch_sub(1, Ordering::Release);
debug_assert_ne!(desc_ref, 0, "reference count underflow");
if desc_ref != 1 {
probes::on_sender_drop(inner.id);
return;
}
core::sync::atomic::fence(Ordering::Acquire);
inner.control.close();
inner.stream.close();
probes::on_sender_close(inner.id);
}
#[inline]
pub unsafe fn drop_receiver(&self, half: Half) {
let inner = self.inner();
probes::on_receiver_drop(inner.id, half);
ensure!(inner
.stream
.close_receiver(&inner.control, half)
.is_continue());
probes::on_receiver_free(inner.id, half);
let storage = inner.free_list.free(Descriptor {
ptr: self.ptr,
phantom: PhantomData,
});
drop(storage);
}
}
unsafe impl<T: Send, Key: Send> Send for Descriptor<T, Key> {}
unsafe impl<T: Sync, Key: Sync> Sync for Descriptor<T, Key> {}
pub(super) struct DescriptorInner<T, Key> {
id: VarInt,
key: UnsafeCell<Option<Key>>,
stream: Queue<T>,
control: Queue<T>,
free_list: Arc<dyn FreeList<T, Key>>,
senders: AtomicUsize,
}
impl<T, Key> DescriptorInner<T, Key> {
pub(super) fn new(
id: VarInt,
stream: ring_deque::Capacity,
control: ring_deque::Capacity,
free_list: Arc<dyn FreeList<T, Key>>,
) -> Self {
let stream = Queue::new(stream, Half::Stream);
let control = Queue::new(control, Half::Control);
Self {
id,
key: UnsafeCell::new(None),
stream,
control,
senders: AtomicUsize::new(0),
free_list,
}
}
}