summaryrefslogtreecommitdiffstats
path: root/third_party/rust/filetime_win/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/filetime_win/src/lib.rs')
-rw-r--r--third_party/rust/filetime_win/src/lib.rs268
1 files changed, 268 insertions, 0 deletions
diff --git a/third_party/rust/filetime_win/src/lib.rs b/third_party/rust/filetime_win/src/lib.rs
new file mode 100644
index 0000000000..04fdb4bb97
--- /dev/null
+++ b/third_party/rust/filetime_win/src/lib.rs
@@ -0,0 +1,268 @@
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// All files in the project carrying such notice may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Windows [`FILETIME`](https://docs.microsoft.com/en-us/windows/desktop/api/minwinbase/ns-minwinbase-filetime)
+//! and [`SYSTEMTIME`](https://docs.microsoft.com/en-us/windows/desktop/api/minwinbase/ns-minwinbase-systemtime)
+//! string and binary serialization
+//!
+//! A transparent wrapper is provided for each type, with
+//! `Display` for [`SystemTimeUTC`](struct.SystemTimeUTC.html) and
+//! `Ord` and `Eq` for [`FileTime`](struct.FileTime.html).
+//!
+//! # serde #
+//!
+//! Use the `filetime_serde` feature to derive `Serialize` and `Deserialize`, you can then
+//! derive them for structs containing `FILETIME` and `SYSTEMTIME` like so:
+//!
+//! ```
+//! # fn main() {}
+//! #
+//! # #[cfg(feature = "filetime_serde")]
+//! # extern crate serde_derive;
+//! # extern crate winapi;
+//! #
+//! # #[cfg(feature = "filetime_serde")]
+//! # mod test {
+//! use filetime_win::{FileTimeSerde, SystemTimeSerde};
+//! use serde_derive::{Deserialize, Serialize};
+//! use winapi::shared::minwindef::FILETIME;
+//! use winapi::um::minwinbase::SYSTEMTIME;
+//!
+//! #[derive(Serialize, Deserialize)]
+//! struct SerdeTest {
+//! #[serde(with = "FileTimeSerde")]
+//! ft: FILETIME,
+//! #[serde(with = "SystemTimeSerde")]
+//! st: SYSTEMTIME,
+//! }
+//! # }
+//! ```
+extern crate comedy;
+#[cfg(feature = "filetime_serde")]
+extern crate serde;
+#[cfg(feature = "filetime_serde")]
+extern crate serde_derive;
+extern crate winapi;
+
+use std::cmp::Ordering;
+use std::fmt::{Debug, Display, Formatter, Result};
+use std::mem;
+use std::result;
+
+use comedy::check_true;
+
+use winapi::shared::minwindef::FILETIME;
+#[cfg(feature = "filetime_serde")]
+use winapi::shared::minwindef::{DWORD, WORD};
+use winapi::shared::ntdef::ULARGE_INTEGER;
+use winapi::um::minwinbase::SYSTEMTIME;
+use winapi::um::sysinfoapi::GetSystemTime;
+use winapi::um::timezoneapi::{FileTimeToSystemTime, SystemTimeToFileTime};
+
+#[cfg(feature = "filetime_serde")]
+use serde_derive::{Deserialize, Serialize};
+
+#[cfg(feature = "filetime_serde")]
+#[allow(non_snake_case)]
+#[derive(Serialize, Deserialize)]
+#[serde(remote = "FILETIME")]
+pub struct FileTimeSerde {
+ dwLowDateTime: DWORD,
+ dwHighDateTime: DWORD,
+}
+
+/// Wraps `FILETIME`
+#[derive(Copy, Clone)]
+#[cfg_attr(feature = "filetime_serde", derive(Serialize, Deserialize))]
+#[repr(transparent)]
+pub struct FileTime(
+ #[cfg_attr(feature = "filetime_serde", serde(with = "FileTimeSerde"))] pub FILETIME,
+);
+
+#[cfg(feature = "filetime_serde")]
+#[allow(non_snake_case)]
+#[derive(Serialize, Deserialize)]
+#[serde(remote = "SYSTEMTIME")]
+pub struct SystemTimeSerde {
+ wYear: WORD,
+ wMonth: WORD,
+ wDayOfWeek: WORD,
+ wDay: WORD,
+ wHour: WORD,
+ wMinute: WORD,
+ wSecond: WORD,
+ wMilliseconds: WORD,
+}
+
+/// Wraps `SYSTEMTIME`
+///
+/// The `SYSTEMTIME` struct can be UTC or local time, but `SystemTimeUTC` should only be used for
+/// UTC.
+///
+#[derive(Copy, Clone)]
+#[cfg_attr(feature = "filetime_serde", derive(Serialize, Deserialize))]
+#[repr(transparent)]
+pub struct SystemTimeUTC(
+ #[cfg_attr(feature = "filetime_serde", serde(with = "SystemTimeSerde"))] pub SYSTEMTIME,
+);
+
+impl FileTime {
+ /// Convert to raw integer
+ ///
+ /// `FILETIME` is 100-nanosecond intervals since January 1, 1601 (UTC), but if the high
+ /// bit is 1 there may be a different interpretation.
+ pub fn to_u64(self) -> u64 {
+ unsafe {
+ let mut v: ULARGE_INTEGER = mem::zeroed();
+ v.s_mut().LowPart = self.0.dwLowDateTime;
+ v.s_mut().HighPart = self.0.dwHighDateTime;
+ *v.QuadPart()
+ }
+ }
+
+ /// Convert to `SystemTimeUTC` via `FileTimeToSystemTime()`
+ pub fn to_system_time_utc(self) -> result::Result<SystemTimeUTC, comedy::Win32Error> {
+ unsafe {
+ let mut system_time = mem::zeroed();
+
+ check_true!(FileTimeToSystemTime(&self.0, &mut system_time))?;
+
+ Ok(SystemTimeUTC(system_time))
+ }
+ }
+}
+
+impl PartialEq for FileTime {
+ fn eq(&self, other: &FileTime) -> bool {
+ self.0.dwLowDateTime == other.0.dwLowDateTime
+ && self.0.dwHighDateTime == other.0.dwHighDateTime
+ }
+}
+
+impl Eq for FileTime {}
+
+impl PartialOrd for FileTime {
+ fn partial_cmp(&self, other: &FileTime) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl Ord for FileTime {
+ fn cmp(&self, other: &FileTime) -> Ordering {
+ self.to_u64().cmp(&other.to_u64())
+ }
+}
+
+impl Debug for FileTime {
+ fn fmt(&self, f: &mut Formatter) -> Result {
+ write!(
+ f,
+ "FileTime {{ dwLowDateTime: {:?}, dwHighDateTime: {:?} }}",
+ self.0.dwLowDateTime, self.0.dwHighDateTime
+ )
+ }
+}
+
+impl SystemTimeUTC {
+ /// Get current system time in UTC via `GetSystemTime()`
+ ///
+ /// "Because the system time can be adjusted either forward or backward, do not compare
+ /// system time readings to determine elapsed time."
+ pub fn now() -> SystemTimeUTC {
+ unsafe {
+ let mut system_time = mem::zeroed();
+ GetSystemTime(&mut system_time);
+ SystemTimeUTC(system_time)
+ }
+ }
+
+ /// Convert to `FileTime` via `SystemTimeToFileTime()`
+ pub fn to_file_time(&self) -> result::Result<FileTime, comedy::Win32Error> {
+ unsafe {
+ let mut file_time = mem::zeroed();
+
+ check_true!(SystemTimeToFileTime(&self.0, &mut file_time))?;
+
+ Ok(FileTime(file_time))
+ }
+ }
+}
+
+impl Debug for SystemTimeUTC {
+ fn fmt(&self, f: &mut Formatter) -> Result {
+ write!(
+ f,
+ concat!(
+ "SystemTimeUTC {{ ",
+ "wYear: {:?}, wMonth: {:?}, wDayOfWeek: {:?}, wDay: {:?}, ",
+ "wHour: {:?}, wMinute: {:?}, wSecond: {:?}, wMilliseconds: {:?} }}"
+ ),
+ self.0.wYear,
+ self.0.wMonth,
+ self.0.wDayOfWeek,
+ self.0.wDay,
+ self.0.wHour,
+ self.0.wMinute,
+ self.0.wSecond,
+ self.0.wMilliseconds
+ )
+ }
+}
+
+/// Format as ISO 8601 date and time: `YYYY-MM-DDThh:mm:ss.fffZ`
+impl Display for SystemTimeUTC {
+ fn fmt(&self, f: &mut Formatter) -> Result {
+ write!(
+ f,
+ "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}.{:03}Z",
+ self.0.wYear,
+ self.0.wMonth,
+ self.0.wDay,
+ self.0.wHour,
+ self.0.wMinute,
+ self.0.wSecond,
+ self.0.wMilliseconds
+ )
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::{FileTime, SystemTimeUTC};
+ use winapi::shared::minwindef::FILETIME;
+ use winapi::um::minwinbase::SYSTEMTIME;
+
+ #[test]
+ fn roundtrip() {
+ let ft = SystemTimeUTC::now().to_file_time().unwrap();
+
+ assert_eq!(ft, ft);
+ assert_eq!(ft, ft.to_system_time_utc().unwrap().to_file_time().unwrap());
+ }
+
+ #[test]
+ fn next_year() {
+ let st_now = SystemTimeUTC::now();
+ let st_next_year = SystemTimeUTC(SYSTEMTIME {
+ wYear: st_now.0.wYear + 1,
+ ..st_now.0
+ });
+
+ let ft_now = st_now.to_file_time().unwrap();
+ let ft_next_year = st_next_year.to_file_time().unwrap();
+ assert!(ft_next_year > ft_now);
+ }
+
+ #[test]
+ fn non_time_filetime() {
+ let ft = FileTime(FILETIME {
+ dwLowDateTime: 0xFFFF_FFFFu32,
+ dwHighDateTime: 0xFFFF_FFFFu32,
+ });
+
+ ft.to_system_time_utc().expect_err("should have failed");
+ }
+}