use core::{mem, ptr};
use drone_core::ffi::{c_void, CStr, CString};
use drone_core::io::SeekFrom;
use drone_fatfs_raw::{
f_close, f_lseek, f_mkfs, f_mount, f_open, f_read, f_size, f_stat, f_sync,
f_tell, f_write, FSIZE_t, BYTE, FF_MAX_SS, FM_ANY, UINT,
};
use file::File;
use file_info::FileInfo;
use fs::Fs;
use result::{Error, Fresult};
pub struct Cmd(pub(crate) CmdKind);
pub(crate) enum CmdKind {
Mkfs(*const CStr),
Mount(CString),
Umount(Fs),
Stat(*const CStr),
Open(*const CStr, BYTE),
Close(File),
Read(*mut File, *mut [u8]),
Write(*mut File, *const [u8]),
Seek(*mut File, SeekFrom),
Fsync(*mut File),
}
#[allow(unions_with_drop_fields)]
pub union CmdRes {
pub(crate) mkfs: Result<(), Error>,
pub(crate) mount: Result<Fs, Error>,
pub(crate) umount: Result<(), Error>,
pub(crate) stat: Result<FileInfo, Error>,
pub(crate) open: Result<File, Error>,
pub(crate) close: Result<(), Error>,
pub(crate) read: Result<usize, Error>,
pub(crate) write: Result<usize, Error>,
pub(crate) seek: Result<u64, Error>,
pub(crate) fsync: Result<(), Error>,
}
unsafe impl Send for Cmd {}
unsafe impl Send for CmdRes {}
impl Cmd {
pub fn run(self) -> CmdRes {
match self {
Cmd(CmdKind::Mkfs(path)) => CmdRes {
mkfs: unsafe {
let mut work: [u8; FF_MAX_SS as usize] = mem::uninitialized();
f_mkfs(
(*path).as_ptr(),
FM_ANY as u8,
0,
&mut work as *mut _ as *mut c_void,
FF_MAX_SS,
).map(|| ())
},
},
Cmd(CmdKind::Mount(path)) => CmdRes {
mount: unsafe {
let mut fs = Fs::new_uninitialized(path);
f_mount(fs.fs.as_mut(), fs.path.as_ptr(), 0).map(|| fs)
},
},
Cmd(CmdKind::Umount(fs)) => CmdRes {
umount: unsafe {
let fr = f_mount(ptr::null_mut(), fs.path.as_ptr(), 0);
drop(fs);
fr.map(|| ())
},
},
Cmd(CmdKind::Stat(path)) => CmdRes {
stat: unsafe {
let mut file_info = FileInfo::new_uninitialized();
f_stat((*path).as_ptr(), file_info.as_raw_mut()).map(|| file_info)
},
},
Cmd(CmdKind::Open(path, mode)) => CmdRes {
open: unsafe {
let mut file = File::new_uninitialized();
f_open(file.as_raw_mut(), (*path).as_ptr(), mode).map(|| file)
},
},
Cmd(CmdKind::Close(mut file)) => CmdRes {
close: unsafe {
let fr = f_close(file.as_raw_mut());
drop(file);
fr.map(|| ())
},
},
Cmd(CmdKind::Read(file, buf)) => CmdRes {
read: unsafe {
let mut br = mem::uninitialized();
f_read(
(*file).as_raw_mut(),
(*buf).as_mut_ptr() as *mut c_void,
(*buf).len() as UINT,
&mut br,
).map(|| br as usize)
},
},
Cmd(CmdKind::Write(file, buf)) => CmdRes {
write: unsafe {
let mut br = mem::uninitialized();
f_write(
(*file).as_raw_mut(),
(*buf).as_ptr() as *const c_void,
(*buf).len() as UINT,
&mut br,
).map(|| br as usize)
},
},
Cmd(CmdKind::Seek(file, pos)) => CmdRes {
seek: unsafe {
let fp = (*file).as_raw_mut();
let pos = match pos {
SeekFrom::Start(pos) => pos as FSIZE_t,
SeekFrom::End(pos) => f_size(fp).wrapping_add(pos as FSIZE_t),
SeekFrom::Current(pos) => f_tell(fp).wrapping_add(pos as FSIZE_t),
};
f_lseek(fp, pos).map(|| u64::from(pos))
},
},
Cmd(CmdKind::Fsync(file)) => CmdRes {
fsync: unsafe { f_sync((*file).as_raw_mut()).map(|| ()) },
},
}
}
}