disk-space 0.1.0

Tiny lib for disk space info of os file system (cross-platform).
Documentation
use std::path::Path;

#[cfg(test)]
mod test;

/// for human readability (read-only)
pub struct DiskSpaceForHuman {
    pub available: f64,
    pub total: f64,
}

/// core struct
pub struct DiskSpace {
    pub available: u64,
    pub total: u64,
}

impl DiskSpace {
    /// new
    pub fn new(path: &Path) -> Result<DiskSpace, std::io::Error> {
        #[cfg(not(windows))]
        {
            use std::ffi::CString;

            let c_path = CString::new(path.to_str().unwrap()).unwrap();
            let mut stat = unsafe { std::mem::zeroed::<libc::statvfs>() };
            let ret = unsafe { libc::statvfs(c_path.as_ptr(), &mut stat) };
            if ret != 0 {
                return Err(std::io::Error::last_os_error());
            }
            Ok(DiskSpace {
                available: stat.f_bavail as u64 * stat.f_frsize as u64,
                total: stat.f_blocks as u64 * stat.f_frsize as u64,
            })
        }

        #[cfg(windows)]
        {
            use std::os::windows::ffi::OsStrExt;
            let wide: Vec<u16> = path.as_os_str().encode_wide().chain([0]).collect();
            let (mut free, mut total, mut tf) = (0u64, 0u64, 0u64);

            #[link(name = "kernel32")]
            unsafe extern "system" {
                fn GetDiskFreeSpaceExW(
                    path: *const u16,
                    free: *mut u64,
                    total: *mut u64,
                    total_free: *mut u64,
                ) -> i32;
            }
            let ok = unsafe { GetDiskFreeSpaceExW(wide.as_ptr(), &mut free, &mut total, &mut tf) };

            if ok == 0 {
                return Err(std::io::Error::last_os_error());
            }
            Ok(DiskSpace {
                available: free,
                total,
            })
        }
    }

    /// info as Megabyte
    pub fn as_mb(&self) -> DiskSpaceForHuman {
        let divisor = 1024u64.pow(2) as f64;
        let (available, total) = (self.available as f64 / divisor, self.total as f64 / divisor);
        DiskSpaceForHuman { available, total }
    }

    /// info as Gigabyte
    pub fn as_gb(&self) -> DiskSpaceForHuman {
        let divisor = 1024u64.pow(3) as f64;
        let (available, total) = (self.available as f64 / divisor, self.total as f64 / divisor);
        DiskSpaceForHuman { available, total }
    }
}