use std::path::{Path, PathBuf};
use windows_sys::Win32::Foundation::{CloseHandle, HANDLE, INVALID_HANDLE_VALUE};
use windows_sys::Win32::Storage::FileSystem::{
CreateFileW, FILE_FLAG_NO_BUFFERING, FILE_FLAG_OVERLAPPED, FILE_GENERIC_READ,
FILE_GENERIC_WRITE, FILE_SHARE_READ, OPEN_ALWAYS,
};
#[derive(Debug, Clone)]
pub struct IocpConfig {
pub concurrent_threads: u32,
pub enable_direct_io: bool,
}
impl Default for IocpConfig {
fn default() -> Self {
Self {
concurrent_threads: 0,
enable_direct_io: false,
}
}
}
pub struct IocpStorageState {
handles: Vec<HANDLE>,
}
impl IocpStorageState {
pub fn open_files(
base_dir: &Path,
file_paths: &[PathBuf],
direct_io: bool,
) -> std::io::Result<Self> {
let mut handles = Vec::with_capacity(file_paths.len());
for path in file_paths {
let full = base_dir.join(path);
let wide: Vec<u16> = std::os::windows::ffi::OsStrExt::encode_wide(full.as_os_str())
.chain(std::iter::once(0))
.collect();
let mut flags = FILE_FLAG_OVERLAPPED;
if direct_io {
flags |= FILE_FLAG_NO_BUFFERING;
}
let handle = unsafe {
CreateFileW(
wide.as_ptr(),
FILE_GENERIC_READ | FILE_GENERIC_WRITE,
FILE_SHARE_READ,
std::ptr::null(),
OPEN_ALWAYS,
flags,
std::ptr::null_mut(),
)
};
if handle == INVALID_HANDLE_VALUE {
for &h in &handles {
unsafe {
CloseHandle(h);
}
}
return Err(std::io::Error::last_os_error());
}
handles.push(handle);
}
Ok(Self { handles })
}
pub fn handle(&self, file_index: usize) -> HANDLE {
self.handles[file_index]
}
#[must_use]
pub fn len(&self) -> usize {
self.handles.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.handles.is_empty()
}
}
impl Drop for IocpStorageState {
fn drop(&mut self) {
for &h in &self.handles {
unsafe {
CloseHandle(h);
}
}
}
}
unsafe impl Send for IocpStorageState {}
unsafe impl Sync for IocpStorageState {}