use std::fs::OpenOptions;
use std::io::{self, Read, Seek, SeekFrom, Write};
use std::path::{Path, PathBuf};
use crate::collective::CommunicatorCollectives;
use crate::datatype::Equivalence;
use crate::topology::{Communicator, SimpleCommunicator};
pub const MODE_RDONLY: u32 = 1;
pub const MODE_WRONLY: u32 = 2;
pub const MODE_RDWR: u32 = 4;
pub const MODE_CREATE: u32 = 8;
pub const MODE_APPEND: u32 = 16;
pub const MODE_EXCL: u32 = 32;
pub const MODE_DELETE_ON_CLOSE: u32 = 64;
#[inline]
fn as_bytes<T>(v: &[T]) -> &[u8] {
unsafe { std::slice::from_raw_parts(v.as_ptr() as *const u8, std::mem::size_of_val(v)) }
}
#[inline]
fn as_bytes_mut<T>(v: &mut [T]) -> &mut [u8] {
unsafe { std::slice::from_raw_parts_mut(v.as_mut_ptr() as *mut u8, std::mem::size_of_val(v)) }
}
pub struct File {
inner: std::fs::File,
comm: SimpleCommunicator,
path: PathBuf,
delete_on_close: bool,
}
impl File {
pub fn open<C: Communicator>(comm: &C, path: impl AsRef<Path>, mode: u32) -> io::Result<File> {
let path = path.as_ref().to_path_buf();
if mode & MODE_CREATE != 0 && comm.rank() == 0 {
let mut oo = OpenOptions::new();
oo.write(true);
if mode & MODE_EXCL != 0 {
oo.create_new(true);
} else {
oo.create(true);
}
let _ = oo.open(&path)?;
}
comm.barrier();
let mut oo = OpenOptions::new();
let read = mode & (MODE_RDONLY | MODE_RDWR) != 0;
let write = mode & (MODE_WRONLY | MODE_RDWR | MODE_APPEND | MODE_CREATE) != 0;
oo.read(read || !write).write(write);
if mode & MODE_APPEND != 0 {
oo.append(true);
}
let inner = oo.open(&path)?;
Ok(File {
inner,
comm: comm.duplicate(),
path,
delete_on_close: mode & MODE_DELETE_ON_CLOSE != 0,
})
}
pub fn write_at<T: Equivalence>(&mut self, offset: u64, data: &[T]) -> io::Result<()> {
self.inner.seek(SeekFrom::Start(offset))?;
self.inner.write_all(as_bytes(data))
}
pub fn read_at<T: Equivalence>(&mut self, offset: u64, buf: &mut [T]) -> io::Result<()> {
self.inner.seek(SeekFrom::Start(offset))?;
self.inner.read_exact(as_bytes_mut(buf))
}
pub fn write_at_all<T: Equivalence>(&mut self, offset: u64, data: &[T]) -> io::Result<()> {
self.comm.barrier();
let r = self.write_at(offset, data);
self.inner.flush()?;
self.comm.barrier();
r
}
pub fn read_at_all<T: Equivalence>(&mut self, offset: u64, buf: &mut [T]) -> io::Result<()> {
self.comm.barrier();
let r = self.read_at(offset, buf);
self.comm.barrier();
r
}
pub fn size(&self) -> io::Result<u64> {
Ok(self.inner.metadata()?.len())
}
pub fn set_size(&mut self, size: u64) -> io::Result<()> {
self.inner.set_len(size)
}
pub fn sync(&mut self) -> io::Result<()> {
self.inner.sync_all()
}
pub fn close(self) -> io::Result<()> {
drop(self);
Ok(())
}
}
impl Drop for File {
fn drop(&mut self) {
let _ = self.inner.sync_all();
if self.delete_on_close {
self.comm.barrier();
if self.comm.rank() == 0 {
let _ = std::fs::remove_file(&self.path);
}
}
}
}