use crate::{message::Message, socket::ring::Consumer};
use core::task::{Context, Poll};
use s2n_quic_core::{
event,
inet::datagram,
io::rx,
path::{LocalAddress, MaxMtu},
task::waker,
};
pub struct Rx<T: Message> {
channels: Vec<Consumer<T>>,
max_mtu: MaxMtu,
local_address: LocalAddress,
}
impl<T: Message> Rx<T> {
#[inline]
pub fn new(channels: Vec<Consumer<T>>, max_mtu: MaxMtu, local_address: LocalAddress) -> Self {
Self {
channels,
max_mtu,
local_address,
}
}
}
impl<T: Message> rx::Rx for Rx<T> {
type PathHandle = T::Handle;
type Queue = RxQueue<'static, T>;
type Error = ();
#[inline]
fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
waker::debug_assert_contract(cx, |cx| {
let mut is_any_ready = false;
let mut is_all_closed = true;
for channel in &mut self.channels {
match channel.poll_acquire(u32::MAX, cx) {
Poll::Ready(_) => {
is_all_closed = false;
is_any_ready = true;
}
Poll::Pending => {
is_all_closed &= !channel.is_open();
}
}
}
if is_all_closed {
return Err(()).into();
}
if is_any_ready {
Poll::Ready(Ok(()))
} else {
Poll::Pending
}
})
}
#[inline]
fn queue<F: FnOnce(&mut Self::Queue)>(&mut self, f: F) {
let this: &'static mut Self = unsafe {
core::mem::transmute(self)
};
let mut queue = RxQueue {
channels: &mut this.channels,
max_mtu: this.max_mtu,
local_address: &this.local_address,
};
f(&mut queue);
}
#[inline]
fn handle_error<E: event::EndpointPublisher>(self, _error: Self::Error, _events: &mut E) {
}
}
pub struct RxQueue<'a, T: Message> {
channels: &'a mut [Consumer<T>],
max_mtu: MaxMtu,
local_address: &'a LocalAddress,
}
impl<T: Message> rx::Queue for RxQueue<'_, T> {
type Handle = T::Handle;
#[inline]
fn for_each<F: FnMut(datagram::Header<Self::Handle>, &mut [u8])>(&mut self, mut on_packet: F) {
for channel in self.channels.iter_mut() {
let len = channel.acquire(u32::MAX);
let data = channel.data();
debug_assert_eq!(data.len(), len as usize);
for message in data {
if let Some(message) = message.rx_read(self.local_address) {
message.for_each(&mut on_packet);
}
unsafe {
message.reset(self.max_mtu.into());
}
}
channel.release(len);
}
}
#[inline]
fn is_empty(&self) -> bool {
false
}
}