use std::num::NonZeroUsize;
use bytes::BufMut;
use tracing::trace;
use crate::packet::BufLen;
#[derive(Debug)]
pub(super) struct TransmitBuf<'a> {
buf: &'a mut Vec<u8>,
datagram_start: usize,
buf_capacity: usize,
max_datagrams: NonZeroUsize,
pub(super) num_datagrams: usize,
segment_size: usize,
}
impl<'a> TransmitBuf<'a> {
pub(super) fn new(buf: &'a mut Vec<u8>, max_datagrams: NonZeroUsize, mtu: usize) -> Self {
buf.clear();
Self {
buf,
datagram_start: 0,
buf_capacity: 0,
max_datagrams,
num_datagrams: 0,
segment_size: mtu,
}
}
pub(super) fn start_new_datagram_with_size(&mut self, datagram_size: usize) {
let max_capacity_hint = datagram_size;
self.new_datagram_inner(datagram_size, max_capacity_hint)
}
pub(super) fn start_new_datagram(&mut self) {
let max_capacity_hint = self.max_datagrams.get() * self.segment_size;
self.new_datagram_inner(self.segment_size, max_capacity_hint)
}
fn new_datagram_inner(&mut self, datagram_size: usize, max_capacity_hint: usize) {
debug_assert!(self.num_datagrams < self.max_datagrams.into());
if self.num_datagrams == 1 {
self.segment_size = self.buf.len();
}
if self.num_datagrams >= 1 {
debug_assert!(datagram_size <= self.segment_size);
if datagram_size < self.segment_size {
self.max_datagrams = NonZeroUsize::MIN.saturating_add(self.num_datagrams);
}
}
self.datagram_start = self.buf.len();
debug_assert_eq!(
self.datagram_start % self.segment_size,
0,
"datagrams in a GSO batch must be aligned to the segment size"
);
self.buf_capacity = self.datagram_start + datagram_size;
if self.buf_capacity > self.buf.capacity() {
self.buf
.reserve_exact(max_capacity_hint.saturating_sub(self.buf.capacity()));
}
self.num_datagrams += 1;
}
pub(super) fn clip_segment_size(&mut self) {
debug_assert_eq!(self.num_datagrams, 1);
if self.buf.len() < self.segment_size {
trace!(
segment_size = self.buf.len(),
prev_segment_size = self.segment_size,
"clipped datagram size"
);
}
self.segment_size = self.buf.len();
self.buf_capacity = self.buf.len();
}
pub(super) fn segment_size(&self) -> usize {
self.segment_size
}
pub(super) fn num_datagrams(&self) -> usize {
self.num_datagrams
}
pub(super) fn max_datagrams(&self) -> NonZeroUsize {
self.max_datagrams
}
pub(super) fn datagram_start_offset(&self) -> usize {
self.datagram_start
}
pub(super) fn datagram_max_offset(&self) -> usize {
self.buf_capacity
}
pub(super) fn datagram_remaining_mut(&self) -> usize {
self.buf_capacity.saturating_sub(self.buf.len())
}
pub(super) fn is_empty(&self) -> bool {
self.len() == 0
}
pub(super) fn len(&self) -> usize {
self.buf.len()
}
pub(super) fn as_mut_slice(&mut self) -> &mut [u8] {
self.buf.as_mut_slice()
}
}
unsafe impl BufMut for TransmitBuf<'_> {
fn remaining_mut(&self) -> usize {
self.buf.remaining_mut()
}
unsafe fn advance_mut(&mut self, cnt: usize) {
unsafe { self.buf.advance_mut(cnt) };
}
fn chunk_mut(&mut self) -> &mut bytes::buf::UninitSlice {
self.buf.chunk_mut()
}
}
impl BufLen for TransmitBuf<'_> {
fn len(&self) -> usize {
self.len()
}
}