use std::borrow::{Borrow, BorrowMut};
use std::mem::MaybeUninit;
use std::ops::{Bound, Deref, DerefMut, RangeBounds};
use std::ptr::{self, NonNull};
use std::sync::Arc;
use std::{fmt, io, slice};
#[cfg(any(target_os = "android", target_os = "linux"))]
use crate::io::BufId;
use crate::io::{Buf, BufMut, BufMutParts};
use crate::{SubmissionQueue, sys};
#[derive(Clone, Debug)]
#[allow(clippy::module_name_repetitions)] pub struct ReadBufPool {
pub(crate) shared: Arc<sys::io::ReadBufPool>,
}
impl ReadBufPool {
#[doc(alias = "IORING_REGISTER_PBUF_RING")]
pub fn new(sq: SubmissionQueue, pool_size: u16, buf_size: u32) -> io::Result<ReadBufPool> {
debug_assert!(pool_size <= 1 << 15);
debug_assert!(pool_size.is_power_of_two());
let shared = sys::io::ReadBufPool::new(sq, pool_size, buf_size)?;
Ok(ReadBufPool {
shared: Arc::new(shared),
})
}
pub fn get(&self) -> ReadBuf {
ReadBuf {
shared: self.shared.clone(),
owned: None,
}
}
#[cfg(any(target_os = "android", target_os = "linux"))]
pub(crate) unsafe fn new_buffer(&self, id: BufId, n: u32) -> ReadBuf {
ReadBuf {
shared: self.shared.clone(),
owned: Some(unsafe { self.shared.init_buffer(id, n) }),
}
}
#[cfg(any(
target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd",
target_os = "tvos",
target_os = "visionos",
target_os = "watchos",
))]
pub(crate) unsafe fn new_buffer(&self, ptr: NonNull<u8>, n: usize) -> ReadBuf {
ReadBuf {
shared: self.shared.clone(),
owned: Some(NonNull::slice_from_raw_parts(ptr, n)),
}
}
#[cfg(any(target_os = "android", target_os = "linux"))]
pub(crate) fn empty_buffer(&self) -> ReadBuf {
ReadBuf {
shared: self.shared.clone(),
owned: None,
}
}
}
pub struct ReadBuf {
pub(crate) shared: Arc<sys::io::ReadBufPool>,
pub(crate) owned: Option<NonNull<[u8]>>,
}
impl ReadBuf {
pub fn capacity(&self) -> usize {
self.shared.buf_size()
}
pub fn len(&self) -> usize {
self.owned.map_or(0, NonNull::len)
}
pub fn is_empty(&self) -> bool {
self.owned.is_none_or(|ptr| ptr.len() == 0)
}
pub fn as_slice(&self) -> &[u8] {
self
}
pub fn as_mut_slice(&mut self) -> &mut [u8] {
self
}
pub fn truncate(&mut self, len: usize) {
if let Some(ptr) = self.owned {
if len > ptr.len() {
return;
}
self.owned = Some(change_size(ptr, len));
}
}
pub fn clear(&mut self) {
if let Some(ptr) = self.owned {
self.owned = Some(change_size(ptr, 0));
}
}
pub fn remove<R: RangeBounds<usize>>(&mut self, range: R) {
let original_len = self.len();
let start = match range.start_bound() {
Bound::Unbounded => 0,
Bound::Included(start_idx) => *start_idx,
Bound::Excluded(start_idx) => start_idx + 1,
};
let end = match range.end_bound() {
Bound::Unbounded => original_len,
Bound::Included(end_idx) => end_idx + 1,
Bound::Excluded(end_idx) => *end_idx,
};
if let Some(ptr) = self.owned {
if start > end {
panic!("slice index starts at {start} but ends at {end}");
} else if end > original_len {
panic!("range end index {end} out of range for slice of length {original_len}");
}
let remove_len = end - start;
let new_len = original_len - remove_len;
self.owned = Some(change_size(ptr, new_len));
if new_len == 0 || start >= new_len {
return;
}
let start_ptr = unsafe { ptr.cast::<u8>().add(end) };
let to_copy = new_len - start;
unsafe {
ptr.cast::<u8>().add(start).copy_from(start_ptr, to_copy);
}
} else if start != 0 && end != 0 {
panic!("attempting to remove range from empty buffer");
}
}
pub unsafe fn set_len(&mut self, new_len: usize) {
debug_assert!(new_len <= self.capacity());
if let Some(ptr) = self.owned {
self.owned = Some(change_size(ptr, new_len));
}
}
#[allow(clippy::result_unit_err)]
pub fn extend_from_slice(&mut self, other: &[u8]) -> Result<(), ()> {
if let Some(ptr) = self.owned {
let new_len = ptr.len() + other.len();
if new_len > self.capacity() {
return Err(());
}
unsafe {
ptr.cast::<u8>()
.add(ptr.len())
.as_ptr()
.copy_from_nonoverlapping(other.as_ptr(), other.len());
}
self.owned = Some(change_size(ptr, new_len));
Ok(())
} else {
Err(())
}
}
#[allow(clippy::needless_pass_by_ref_mut)] pub fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit<u8>] {
if let Some(ptr) = self.owned {
let unused_len = self.capacity() - ptr.len();
let data = unsafe { ptr.as_ptr().cast::<u8>().add(ptr.len()) };
unsafe { slice::from_raw_parts_mut(data.cast(), unused_len) }
} else {
&mut []
}
}
pub fn release(&mut self) {
if let Some(ptr) = self.owned.take() {
unsafe { self.shared.release(ptr) }
}
}
}
const fn change_size<T>(slice: NonNull<[T]>, new_len: usize) -> NonNull<[T]> {
NonNull::slice_from_raw_parts(slice.cast(), new_len)
}
unsafe impl BufMut for ReadBuf {
unsafe fn parts_mut(&mut self) -> (*mut u8, u32) {
if let Some(ptr) = self.owned {
let len = (self.capacity() - ptr.len()) as u32;
unsafe { (ptr.cast::<u8>().add(ptr.len()).as_ptr(), len) }
} else {
(ptr::null_mut(), 0)
}
}
unsafe fn set_init(&mut self, n: usize) {
if let Some(ptr) = self.owned {
self.owned = Some(change_size(ptr, ptr.len() + n));
} else {
}
}
fn spare_capacity(&self) -> u32 {
if let Some(ptr) = self.owned {
(self.capacity() - ptr.len()) as u32
} else {
0
}
}
fn has_spare_capacity(&self) -> bool {
if let Some(ptr) = self.owned {
self.capacity() > ptr.len()
} else {
false
}
}
#[allow(private_interfaces)]
fn parts(&mut self) -> BufMutParts {
if let Some(ptr) = self.owned {
let len = (self.capacity() - ptr.len()) as u32;
let ptr = unsafe { ptr.cast::<u8>().add(ptr.len()).as_ptr() };
BufMutParts::Buf { ptr, len }
} else {
self.parts_sys()
}
}
#[cfg(any(target_os = "android", target_os = "linux"))]
unsafe fn buffer_init(&mut self, id: BufId, n: u32) {
if let Some(ptr) = self.owned {
debug_assert!(id.0 == 0);
self.owned = Some(change_size(ptr, ptr.len() + n as usize));
} else {
self.owned = Some(unsafe { self.shared.init_buffer(id, n) });
}
}
#[cfg(any(
target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd",
target_os = "tvos",
target_os = "visionos",
target_os = "watchos",
))]
fn release(&mut self) {
self.release();
}
}
unsafe impl Buf for ReadBuf {
unsafe fn parts(&self) -> (*const u8, u32) {
let slice = self.as_slice();
(slice.as_ptr().cast(), slice.len() as u32)
}
}
impl Deref for ReadBuf {
type Target = [u8];
fn deref(&self) -> &Self::Target {
self.owned.map_or(&[], |ptr| unsafe { ptr.as_ref() })
}
}
impl DerefMut for ReadBuf {
fn deref_mut(&mut self) -> &mut Self::Target {
self.owned
.map_or(&mut [], |mut ptr| unsafe { ptr.as_mut() })
}
}
impl AsRef<[u8]> for ReadBuf {
fn as_ref(&self) -> &[u8] {
self
}
}
impl AsMut<[u8]> for ReadBuf {
fn as_mut(&mut self) -> &mut [u8] {
self
}
}
impl Borrow<[u8]> for ReadBuf {
fn borrow(&self) -> &[u8] {
self
}
}
impl BorrowMut<[u8]> for ReadBuf {
fn borrow_mut(&mut self) -> &mut [u8] {
self
}
}
impl fmt::Debug for ReadBuf {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.as_slice().fmt(f)
}
}
unsafe impl Sync for ReadBuf {}
unsafe impl Send for ReadBuf {}
impl Drop for ReadBuf {
fn drop(&mut self) {
self.release();
}
}