use crate::{
error::{Error, Result},
metadata::{DiskMetaData, EmptyMetaData, MemoryMetaData},
MetaData,
};
use std::{
os::windows::fs::MetadataExt,
time::{SystemTime, UNIX_EPOCH},
};
#[enum_dispatch]
pub trait MetaDataExt {
fn accessed(&self) -> std::result::Result<SystemTime, Error>;
fn created(&self) -> std::result::Result<SystemTime, Error>;
fn is_file(&self) -> bool;
fn is_symlink(&self) -> bool;
fn len(&self) -> u64;
fn modified(&self) -> std::result::Result<SystemTime, Error>;
fn file_attributes(&self) -> u32;
fn creation_time(&self) -> u64;
fn last_access_time(&self) -> u64;
fn last_write_time(&self) -> u64;
fn file_size(&self) -> u64;
}
#[cfg(windows)]
impl MetaDataExt for MemoryMetaData {
fn accessed(&self) -> Result<SystemTime> {
Ok(self.create_at)
}
#[inline]
fn created(&self) -> Result<SystemTime> {
Ok(self.create_at)
}
fn is_file(&self) -> bool {
false
}
fn is_symlink(&self) -> bool {
false
}
#[inline]
fn len(&self) -> u64 {
self.size
}
fn modified(&self) -> Result<SystemTime> {
Ok(self.create_at)
}
fn file_attributes(&self) -> u32 {
0
}
fn creation_time(&self) -> u64 {
self.create_at.duration_since(UNIX_EPOCH).unwrap().as_secs()
}
fn last_access_time(&self) -> u64 {
self.create_at.duration_since(UNIX_EPOCH).unwrap().as_secs()
}
fn last_write_time(&self) -> u64 {
self.create_at.duration_since(UNIX_EPOCH).unwrap().as_secs()
}
fn file_size(&self) -> u64 {
self.size
}
}
#[cfg(windows)]
impl MetaDataExt for DiskMetaData {
fn accessed(&self) -> Result<SystemTime> {
self.inner.accessed()
}
fn created(&self) -> Result<SystemTime> {
self.inner.created()
}
fn is_file(&self) -> bool {
self.inner.is_file()
}
fn is_symlink(&self) -> bool {
self.inner.is_symlink()
}
fn len(&self) -> u64 {
self.inner.len()
}
fn modified(&self) -> Result<SystemTime> {
self.inner.modified()
}
fn file_attributes(&self) -> u32 {
self.inner.file_attributes()
}
fn creation_time(&self) -> u64 {
self.inner.creation_time()
}
fn last_access_time(&self) -> u64 {
self.inner.last_access_time()
}
fn last_write_time(&self) -> u64 {
self.inner.last_write_time()
}
fn file_size(&self) -> u64 {
self.inner.file_size()
}
}
#[cfg(windows)]
impl MetaDataExt for EmptyMetaData {
fn accessed(&self) -> Result<SystemTime> {
Ok(UNIX_EPOCH)
}
fn created(&self) -> Result<SystemTime> {
Ok(UNIX_EPOCH)
}
fn is_file(&self) -> bool {
false
}
fn is_symlink(&self) -> bool {
false
}
fn len(&self) -> u64 {
0
}
fn modified(&self) -> Result<SystemTime> {
Ok(UNIX_EPOCH)
}
fn file_attributes(&self) -> u32 {
0
}
fn creation_time(&self) -> u64 {
0
}
fn last_access_time(&self) -> u64 {
0
}
fn last_write_time(&self) -> u64 {
0
}
fn file_size(&self) -> u64 {
0
}
}
#[cfg(windows)]
impl MetaDataExt for MetaData {
fn accessed(&self) -> std::result::Result<SystemTime, Error> {
self.inner.accessed()
}
fn created(&self) -> std::result::Result<SystemTime, Error> {
self.inner.created()
}
fn is_file(&self) -> bool {
self.inner.is_file()
}
fn is_symlink(&self) -> bool {
self.inner.is_symlink()
}
fn len(&self) -> u64 {
self.inner.len()
}
fn modified(&self) -> std::result::Result<SystemTime, Error> {
self.inner.modified()
}
fn file_attributes(&self) -> u32 {
self.inner.file_attributes()
}
fn creation_time(&self) -> u64 {
self.inner.creation_time()
}
fn last_access_time(&self) -> u64 {
self.inner.last_access_time()
}
fn last_write_time(&self) -> u64 {
self.inner.last_write_time()
}
fn file_size(&self) -> u64 {
self.inner.file_size()
}
}
#[cfg(all(test, feature = "sync"))]
mod tests {
use crate::{
empty::EmptyMmapFile, raw::MemoryMmapFile, tests::get_random_filename, MetaDataExt,
MmapFileExt, MmapFileMutExt, Options,
};
use bytes::Bytes;
use std::time::UNIX_EPOCH;
#[test]
fn test_metadata() {
let mut file = unsafe {
Options::new()
.max_size("Hello, fmmap!".len() as u64)
.create_mmap_file_mut(get_random_filename())
}
.unwrap();
file.set_remove_on_drop(true);
file.write_all("Hello, fmmap!".as_bytes(), 0).unwrap();
let meta = file.metadata().unwrap();
meta.accessed().unwrap();
meta.created().unwrap();
assert!(meta.is_file());
assert!(!meta.is_symlink());
assert_eq!(meta.len(), "Hello, fmmap!".len() as u64);
assert_eq!(meta.file_size(), "Hello, fmmap!".len() as u64);
meta.file_attributes();
meta.creation_time();
meta.last_access_time();
meta.last_write_time();
}
#[test]
fn test_memory_metadata() {
let file = MemoryMmapFile::new("test.mem", Bytes::from("Hello, fmmap!"));
let meta = file.metadata().unwrap();
assert!(!meta.is_file());
assert!(!meta.is_symlink());
assert_eq!(meta.len(), "Hello, fmmap!".len() as u64);
assert_eq!(meta.file_size(), "Hello, fmmap!".len() as u64);
assert_eq!(meta.file_attributes(), 0);
assert!(
meta.modified().unwrap() == meta.created().unwrap()
&& meta.created().unwrap() == meta.accessed().unwrap()
);
assert!(
meta.creation_time() == meta.last_access_time()
&& meta.last_access_time() == meta.last_write_time()
);
}
#[test]
fn test_empty_metadata() {
let file = EmptyMmapFile::default();
let meta = file.metadata().unwrap();
assert_eq!(meta.accessed().unwrap(), UNIX_EPOCH);
assert_eq!(meta.created().unwrap(), UNIX_EPOCH);
assert!(!meta.is_file());
assert!(!meta.is_symlink());
assert_eq!(meta.len(), 0);
assert_eq!(meta.modified().unwrap(), UNIX_EPOCH);
assert_eq!(meta.file_attributes(), 0);
assert_eq!(meta.creation_time(), 0);
assert_eq!(meta.last_access_time(), 0);
assert_eq!(meta.last_write_time(), 0);
assert_eq!(meta.file_size(), 0);
}
}