#![allow(clippy::unnecessary_wraps)]
use std::os::fd::AsRawFd;
use io_uring::{opcode, types};
use wireshift_core::op::OpDescriptor;
use wireshift_core::{Error, Result};
use super::PreparedEntry;
use crate::file_registry::FileRegistryTable;
use crate::types::InflightData;
pub(crate) fn build_read(
descriptor: &OpDescriptor,
id: u64,
fixed_files: &FileRegistryTable,
) -> Result<Vec<PreparedEntry>> {
let OpDescriptor::Read {
file,
offset,
buffer,
len,
} = descriptor
else {
unreachable!()
};
let read_len = len.unwrap_or_else(|| buffer.capacity());
let len_u32 = u32::try_from(read_len).map_err(|_| {
Error::validation(
"read buffer length exceeds io_uring's u32 limit",
"use smaller buffers for native io_uring reads",
)
})?;
let entry = if let Some(slot) = fixed_files.lookup(file.as_raw_fd()) {
opcode::Read::new(
types::Fixed(slot),
buffer.backend_ref().as_ptr().cast_mut(),
len_u32,
)
} else {
opcode::Read::new(
types::Fd(file.as_raw_fd()),
buffer.backend_ref().as_ptr().cast_mut(),
len_u32,
)
}
.offset(*offset)
.build()
.user_data(id);
Ok(vec![PreparedEntry {
entry,
pinned: InflightData::None,
link_to_next: None,
}])
}
pub(crate) fn build_read_fixed(
descriptor: &OpDescriptor,
id: u64,
_fixed_files: &FileRegistryTable,
) -> Result<Vec<PreparedEntry>> {
let OpDescriptor::ReadFixed {
slot,
offset,
buffer,
} = descriptor
else {
unreachable!()
};
let len = u32::try_from(buffer.capacity()).map_err(|_| {
Error::validation(
"read buffer length exceeds io_uring's u32 limit",
"use smaller buffers for native io_uring reads",
)
})?;
let entry = opcode::Read::new(
types::Fixed(*slot),
buffer.backend_ref().as_ptr().cast_mut(),
len,
)
.offset(*offset)
.build()
.user_data(id);
Ok(vec![PreparedEntry {
entry,
pinned: InflightData::None,
link_to_next: None,
}])
}
pub(crate) fn build_read_gpu(
descriptor: &OpDescriptor,
id: u64,
fixed_files: &FileRegistryTable,
) -> Result<Vec<PreparedEntry>> {
let OpDescriptor::ReadGpu {
file,
offset,
buffer,
} = descriptor
else {
unreachable!()
};
let len = u32::try_from(buffer.capacity()).map_err(|_| {
Error::validation(
"gpu staging buffer length exceeds io_uring's u32 limit",
"use smaller buffers for native GPU-staged reads",
)
})?;
let entry = if let Some(slot) = fixed_files.lookup(file.as_raw_fd()) {
opcode::Read::new(
types::Fixed(slot),
buffer.as_slice().as_ptr().cast_mut(),
len,
)
} else {
opcode::Read::new(
types::Fd(file.as_raw_fd()),
buffer.as_slice().as_ptr().cast_mut(),
len,
)
}
.offset(*offset)
.build()
.user_data(id);
Ok(vec![PreparedEntry {
entry,
pinned: InflightData::None,
link_to_next: None,
}])
}
pub(crate) fn build_write(
descriptor: &OpDescriptor,
id: u64,
fixed_files: &FileRegistryTable,
) -> Result<Vec<PreparedEntry>> {
let OpDescriptor::Write {
file,
offset,
buffer,
} = descriptor
else {
unreachable!()
};
let len = u32::try_from(buffer.filled_len()).map_err(|_| {
Error::validation(
"write buffer length exceeds io_uring's u32 limit",
"use smaller buffers for native io_uring writes",
)
})?;
let entry = if let Some(slot) = fixed_files.lookup(file.as_raw_fd()) {
opcode::Write::new(types::Fixed(slot), buffer.backend_ref().as_ptr(), len)
} else {
opcode::Write::new(
types::Fd(file.as_raw_fd()),
buffer.backend_ref().as_ptr(),
len,
)
}
.offset(*offset)
.build()
.user_data(id);
Ok(vec![PreparedEntry {
entry,
pinned: InflightData::None,
link_to_next: None,
}])
}
pub(crate) fn build_read_vectored(
descriptor: &OpDescriptor,
id: u64,
fixed_files: &FileRegistryTable,
) -> Result<Vec<PreparedEntry>> {
let OpDescriptor::ReadVectored {
file,
offset,
buffers,
} = descriptor
else {
unreachable!()
};
let iovecs: Vec<libc::iovec> = buffers
.iter()
.map(|buf| libc::iovec {
iov_base: buf.backend_ref().as_ptr().cast_mut().cast::<libc::c_void>(),
iov_len: buf.capacity(),
})
.collect();
let entry = if let Some(slot) = fixed_files.lookup(file.as_raw_fd()) {
opcode::Readv::new(
types::Fixed(slot),
iovecs.as_ptr().cast(),
iovecs.len() as u32,
)
} else {
opcode::Readv::new(
types::Fd(file.as_raw_fd()),
iovecs.as_ptr().cast(),
iovecs.len() as u32,
)
}
.offset(*offset)
.build()
.user_data(id);
Ok(vec![PreparedEntry {
entry,
pinned: InflightData::Iovec(iovecs),
link_to_next: None,
}])
}
pub(crate) fn build_write_vectored(
descriptor: &OpDescriptor,
id: u64,
fixed_files: &FileRegistryTable,
) -> Result<Vec<PreparedEntry>> {
let OpDescriptor::WriteVectored {
file,
offset,
buffers,
} = descriptor
else {
unreachable!()
};
let iovecs: Vec<libc::iovec> = buffers
.iter()
.map(|buf| libc::iovec {
iov_base: buf.backend_ref().as_ptr().cast_mut().cast::<libc::c_void>(),
iov_len: buf.filled_len(),
})
.collect();
let entry = if let Some(slot) = fixed_files.lookup(file.as_raw_fd()) {
opcode::Writev::new(
types::Fixed(slot),
iovecs.as_ptr().cast(),
iovecs.len() as u32,
)
} else {
opcode::Writev::new(
types::Fd(file.as_raw_fd()),
iovecs.as_ptr().cast(),
iovecs.len() as u32,
)
}
.offset(*offset)
.build()
.user_data(id);
Ok(vec![PreparedEntry {
entry,
pinned: InflightData::Iovec(iovecs),
link_to_next: None,
}])
}