use std::os::windows::fs::MetadataExt;
use std::time::{SystemTime, UNIX_EPOCH};
use crate::error::{Error, ErrorKind, Result};
use crate::MetaData;
use crate::metadata::{DiskMetaData, EmptyMetaData, MemoryMetaData};
#[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;
#[cfg(feature = "nightly")]
#[cfg_attr(docsrs, doc(cfg(feature = "nightly")))]
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(feature = "nightly")]
#[cfg_attr(docsrs, doc(cfg(feature = "nightly")))]
fn volume_serial_number(&self) -> Option<u32>;
#[cfg(feature = "nightly")]
#[cfg_attr(docsrs, doc(cfg(feature = "nightly")))]
fn number_of_links(&self) -> Option<u32>;
#[cfg(feature = "nightly")]
#[cfg_attr(docsrs, doc(cfg(feature = "nightly")))]
fn file_index(&self) -> Option<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
}
#[cfg(feature = "nightly")]
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(feature = "nightly")]
#[cfg_attr(docsrs, doc(cfg(feature = "nightly")))]
fn volume_serial_number(&self) -> Option<u32> {
None
}
#[cfg(feature = "nightly")]
#[cfg_attr(docsrs, doc(cfg(feature = "nightly")))]
fn number_of_links(&self) -> Option<u32> {
None
}
#[cfg(feature = "nightly")]
#[cfg_attr(docsrs, doc(cfg(feature = "nightly")))]
fn file_index(&self) -> Option<u64> {
None
}
}
#[cfg(windows)]
impl MetaDataExt for DiskMetaData {
fn accessed(&self) -> Result<SystemTime> {
self.inner.accessed().map_err(|e| Error::new(ErrorKind::IO, e))
}
fn created(&self) -> Result<SystemTime> {
self.inner.created().map_err(|e| Error::new(ErrorKind::IO, e))
}
fn is_file(&self) -> bool {
self.inner.is_file()
}
#[cfg(feature = "nightly")]
#[cfg_attr(docsrs, doc(cfg(feature = "nightly")))]
fn is_symlink(&self) -> bool {
self.inner.is_symlink()
}
fn len(&self) -> u64 {
self.inner.len()
}
fn modified(&self) -> Result<SystemTime> {
self.inner.modified().map_err(|e| Error::new(ErrorKind::IO, e))
}
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(feature = "nightly")]
#[cfg_attr(docsrs, doc(cfg(feature = "nightly")))]
fn volume_serial_number(&self) -> Option<u32> {
self.inner.volume_serial_number()
}
#[cfg(feature = "nightly")]
#[cfg_attr(docsrs, doc(cfg(feature = "nightly")))]
fn number_of_links(&self) -> Option<u32> {
self.inner.number_of_links()
}
#[cfg(feature = "nightly")]
#[cfg_attr(docsrs, doc(cfg(feature = "nightly")))]
fn file_index(&self) -> Option<u64> {
self.inner.file_index()
}
}
#[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
}
#[cfg(feature = "nightly")]
#[cfg_attr(docsrs, doc(cfg(feature = "nightly")))]
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(feature = "nightly")]
#[cfg_attr(docsrs, doc(cfg(feature = "nightly")))]
fn volume_serial_number(&self) -> Option<u32> {
None
}
#[cfg(feature = "nightly")]
#[cfg_attr(docsrs, doc(cfg(feature = "nightly")))]
fn number_of_links(&self) -> Option<u32> {
None
}
#[cfg(feature = "nightly")]
#[cfg_attr(docsrs, doc(cfg(feature = "nightly")))]
fn file_index(&self) -> Option<u64> {
None
}
}
#[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()
}
#[cfg(feature = "nightly")]
#[cfg_attr(docsrs, doc(cfg(feature = "nightly")))]
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(feature = "nightly")]
#[cfg_attr(docsrs, doc(cfg(feature = "nightly")))]
fn volume_serial_number(&self) -> Option<u32> {
self.inner.volume_serial_number()
}
#[cfg(feature = "nightly")]
#[cfg_attr(docsrs, doc(cfg(feature = "nightly")))]
fn number_of_links(&self) -> Option<u32> {
self.inner.number_of_links()
}
#[cfg(feature = "nightly")]
#[cfg_attr(docsrs, doc(cfg(feature = "nightly")))]
fn file_index(&self) -> Option<u64> {
self.inner.file_index()
}
}
#[cfg(test)]
mod tests {
use std::time::UNIX_EPOCH;
use bytes::Bytes;
use crate::empty::EmptyMmapFile;
use crate::{MetaDataExt, MmapFileExt, MmapFileMutExt, Options};
use crate::raw::MemoryMmapFile;
use crate::tests::get_random_filename;
#[test]
fn test_metadata() {
let mut file = 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());
#[cfg(feature = "nightly")]
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();
#[cfg(feature = "nightly")]
assert!(meta.volume_serial_number().is_some());
#[cfg(feature = "nightly")]
assert!(meta.number_of_links().is_some());
#[cfg(feature = "nightly")]
assert!(meta.file_index().is_some());
}
#[test]
fn test_memory_metadata() {
let file = MemoryMmapFile::new("test.mem", Bytes::from("Hello, fmmap!"));
let meta = file.metadata().unwrap();
assert!(!meta.is_file());
#[cfg(feature = "nightly")]
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());
#[cfg(feature = "nightly")]
assert_eq!(meta.volume_serial_number(), None);
#[cfg(feature = "nightly")]
assert_eq!(meta.number_of_links(), None);
#[cfg(feature = "nightly")]
assert_eq!(meta.file_index(), None);
}
#[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());
#[cfg(feature = "nightly")]
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);
#[cfg(feature = "nightly")]
assert_eq!(meta.volume_serial_number(), None);
#[cfg(feature = "nightly")]
assert_eq!(meta.number_of_links(), None);
#[cfg(feature = "nightly")]
assert_eq!(meta.file_index(), None);
}
}