use crate::WriteBufStorage;
use std::pin::Pin;
use std::task::{Context, Poll};
use dope_core::driver::PoolDriver;
use dope_core::profile::Profile;
use dope_transport::Transport;
use super::super::Pool;
use super::super::slot::CoreSlot;
use super::Server;
use super::state::SlotEgress;
use super::wake::WakeQueue;
use crate::SlotId;
use crate::protocol::server::{ResponseChunkStream, ServerProtocol};
impl<H: ServerProtocol, T: Transport, F: Profile, B: PoolDriver> Pool<Server<H, T>, F, B> {
pub(super) fn encode_stream_chunks_to_buf(&mut self, slot_idx: usize) {
let conn_id = {
let conn = &self.core.slots[slot_idx].conn;
SlotId::from_parts(slot_idx as u32, conn.generation)
};
let waker = WakeQueue::make_waker(conn_id);
let mut cx = Context::from_waker(&waker);
let CoreSlot {
conn, buf, user, ..
} = &mut self.core.slots[slot_idx];
let user = user.get_mut();
let SlotEgress::Stream(stream_state) = &mut user.egress else {
return;
};
if stream_state.cur_chunk.is_some() {
return;
}
let mut head = conn.write_head as usize;
let cap = buf.write_buf.as_slice().len();
loop {
if stream_state.eof {
break;
}
let polled: Poll<Option<dambi::Bytes>> = {
let stream: Pin<&mut dyn ResponseChunkStream> = stream_state.stream.as_mut();
stream.poll_chunk(&mut cx)
};
match polled {
Poll::Pending => break,
Poll::Ready(None) => {
stream_state.eof = true;
break;
}
Poll::Ready(Some(chunk)) => {
if chunk.is_empty() {
continue;
}
if cap.saturating_sub(head) < chunk.len() {
stream_state.cur_chunk = Some(chunk);
stream_state.cur_chunk_offset = 0;
break;
}
buf.write_buf.as_mut_slice()[head..head + chunk.len()].copy_from_slice(&chunk);
head += chunk.len();
}
}
}
conn.write_head = head.min(u16::MAX as usize) as u16;
if stream_state.eof && stream_state.cur_chunk.is_none() {
user.egress = SlotEgress::Idle;
}
}
pub(super) fn submit_stream_write(&mut self, driver: &mut B::Driver, slot_idx: usize) {
if self.core.slots[slot_idx].io.write.has_in_flight {
return;
}
let needs_poll = {
let user = self.core.slots[slot_idx].user.get();
match &user.egress {
SlotEgress::Stream(s) => !s.eof && s.cur_chunk.is_none(),
_ => return,
}
};
if needs_poll {
let conn_id = {
let conn = &self.core.slots[slot_idx].conn;
SlotId::from_parts(slot_idx as u32, conn.generation)
};
let waker = WakeQueue::make_waker(conn_id);
let mut cx = Context::from_waker(&waker);
let user = self.core.slots[slot_idx].user.get_mut();
let SlotEgress::Stream(stream_state) = &mut user.egress else {
return;
};
let polled: Poll<Option<dambi::Bytes>> = {
let stream: Pin<&mut dyn ResponseChunkStream> = stream_state.stream.as_mut();
stream.poll_chunk(&mut cx)
};
match polled {
Poll::Pending => return,
Poll::Ready(None) => {
stream_state.eof = true;
user.egress = SlotEgress::Idle;
return;
}
Poll::Ready(Some(chunk)) => {
if chunk.is_empty() {
return;
}
stream_state.cur_chunk = Some(chunk);
stream_state.cur_chunk_offset = 0;
}
}
}
let (ptr, len) = {
let user = self.core.slots[slot_idx].user.get();
let SlotEgress::Stream(s) = &user.egress else {
return;
};
let chunk = s.cur_chunk.as_ref().expect("just stashed");
let off = s.cur_chunk_offset as usize;
let ptr = unsafe { chunk.as_ptr().add(off) };
let len = chunk.len() - off;
(ptr, len)
};
let _ = self.driver_submit_send(driver, slot_idx, ptr, len as u32);
}
}