#![allow(clippy::missing_safety_doc)]
use std::ops::Range;
use libc::{c_void, iovec};
use serde::de::{self, Error};
use serde::{ser::SerializeSeq, Serialize, Serializer};
use crate::utils::{intersection, iovec_as_slice, iovec_as_slice_mut, iovec_as_static_slice};
#[derive(Clone, Debug, PartialEq)]
pub struct SgList {
pub(crate) iovec: *const iovec,
pub(crate) count: usize,
}
impl SgList {
pub fn new(iovec: *const iovec, count: usize) -> Self {
Self { iovec, count }
}
pub fn into_inner(self) -> (*const iovec, usize) {
(self.iovec, self.count)
}
pub unsafe fn index_ref_unchecked(&self, idx: isize) -> &iovec {
&(*self.iovec.offset(idx))
}
pub unsafe fn index_unchecked(&self, idx: isize) -> iovec {
*self.iovec.offset(idx)
}
#[allow(clippy::cast_sign_loss, clippy::cast_possible_wrap)]
pub unsafe fn iter(&self) -> impl Iterator<Item = &iovec> {
(0..self.count as isize).map(move |idx| self.index_ref_unchecked(idx))
}
#[allow(clippy::cast_sign_loss, clippy::cast_possible_wrap)]
pub unsafe fn into_iter(self) -> impl Iterator<Item = iovec> {
(0..self.count as isize).map(move |idx| self.index_unchecked(idx))
}
pub unsafe fn iter_slices(&self) -> impl Iterator<Item = &[u8]> {
self.iter().map(|iov| iovec_as_slice(iov))
}
pub unsafe fn iter_static_slices(self) -> impl Iterator<Item = &'static [u8]> {
self.into_iter().map(|iov| iovec_as_static_slice(iov))
}
pub unsafe fn iter_slices_mut(&mut self) -> impl Iterator<Item = &mut [u8]> {
self.iter().map(|iov| iovec_as_slice_mut(iov))
}
pub unsafe fn ranges(&self) -> impl Iterator<Item = Range<usize>> + '_ {
let mut offset = 0;
self.iter().map(move |iov| {
let start = offset;
offset += iov.iov_len;
start..offset
})
}
pub unsafe fn iter_range(&self) -> impl Iterator<Item = (&iovec, Range<usize>)> {
self.iter().zip(self.ranges())
}
pub unsafe fn iter_slices_range(&self) -> impl Iterator<Item = (&[u8], Range<usize>)> {
self.iter_slices().zip(self.ranges())
}
pub unsafe fn iter_slices_range_mut(
&mut self,
) -> impl Iterator<Item = (&mut [u8], Range<usize>)> {
let ranges = self.ranges().collect::<tinyvec::TinyVec<[_; 8]>>();
self.iter_slices_mut().zip(ranges)
}
pub unsafe fn iter_masked(&self, mask: Range<usize>) -> impl Iterator<Item = iovec> + '_ {
self.iter_range().filter_map(move |(iov, range)| {
intersection(&range, &mask).map(|overlap| {
let adjust_start = overlap.start - range.start;
let adjust_end = range.end - overlap.end;
adjusted(iov, adjust_start, adjust_end)
})
})
}
pub fn size(&self) -> usize {
self.count
}
pub fn is_empty(&self) -> bool {
self.size() == 0
}
pub unsafe fn capacity(&self) -> usize {
self.iter().map(|iov| iov.iov_len).sum()
}
}
fn adjusted(iov: &iovec, start: usize, end: usize) -> iovec {
let iov_base = (iov.iov_base as usize + start) as *mut c_void;
let iov_len = iov.iov_len - end;
iovec { iov_base, iov_len }
}
impl Serialize for SgList {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let length = unsafe { self.capacity() };
let mut seq = serializer.serialize_seq(Some(length))?;
for slice in unsafe { self.iter_slices() } {
for byte in slice {
seq.serialize_element(byte)?
}
}
seq.end()
}
}
impl<'de> de::Deserialize<'de> for SgList {
fn deserialize<D>(_deserializer: D) -> Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
Err(D::Error::custom("Cannot deserialize SgList"))
}
}
#[cfg(test)]
mod tests {
use super::*;
fn assert_overlap(r1: Range<usize>, r2: Range<usize>, r3: &Option<Range<usize>>) {
assert_eq!(&intersection(&r1, &r2), r3);
}
#[test]
fn overlapping() {
assert_overlap(1..3, 4..6, &None);
assert_overlap(1..4, 4..6, &None);
assert_overlap(1..5, 4..6, &Some(4..5));
assert_overlap(1..6, 4..6, &Some(4..6));
assert_overlap(1..7, 4..6, &Some(4..6));
assert_overlap(4..5, 4..6, &Some(4..5));
assert_overlap(4..6, 4..6, &Some(4..6));
assert_overlap(4..7, 4..6, &Some(4..6));
assert_overlap(5..6, 4..6, &Some(5..6));
assert_overlap(5..7, 4..6, &Some(5..6));
assert_overlap(6..7, 4..6, &None);
}
}