Skip to content

Use SystemTime to implement DateTime and provide interop #817

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions crates/gen/src/types/datetime.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use super::*;

pub fn gen_datetime(runtime_type: TokenStream) -> TokenStream {
quote! {
#[repr(transparent)]
#[derive(::std::clone::Clone, ::std::marker::Copy, ::std::cmp::PartialEq, ::std::cmp::Eq, ::std::fmt::Debug)]
pub struct DateTime(::std::time::SystemTime);

// SAFETY: relies on [`std::time::SystemTime`](std::time::SystemTime) wrapping `FILETIME` internally on Windows.
// That means monitoring [implementation of `std::sys::time::SystemTime` on Windows](https://github.com/rust-lang/rust/blob/master/library/std/src/sys/windows/time.rs) for any future change.
unsafe impl ::windows::Abi for DateTime {
type Abi = Self;
}
#runtime_type
impl ::std::convert::From<::std::time::SystemTime> for DateTime {
fn from(value: ::std::time::SystemTime) -> Self {
Self(value)
}
}
impl ::std::convert::From<DateTime> for ::std::time::SystemTime {
fn from(value: DateTime) -> Self {
value.0
}
}
impl<'a> ::windows::IntoParam<'a, DateTime> for ::std::time::SystemTime {
fn into_param(self) -> ::windows::Param<'a, DateTime> {
::windows::Param::Owned(self.into())
}
}
}
}
2 changes: 2 additions & 0 deletions crates/gen/src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ mod callback;
mod class;
mod com_interface;
mod constant;
mod datetime;
mod delegate;
mod r#enum;
mod function;
Expand All @@ -27,6 +28,7 @@ pub use callback::*;
pub use class::*;
pub use com_interface::*;
pub use constant::*;
pub use datetime::*;
pub use delegate::*;
pub use function::*;
pub use handle::*;
Expand Down
31 changes: 19 additions & 12 deletions crates/gen/src/types/struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,18 +154,7 @@ impl Struct {
_ => false,
});

let runtime_type = if is_winrt {
let signature = Literal::byte_string(&self.type_signature().as_bytes());

quote! {
unsafe impl ::windows::RuntimeType for #name {
type DefaultType = Self;
const SIGNATURE: ::windows::ConstBuffer = ::windows::ConstBuffer::from_slice(#signature);
}
}
} else {
quote! {}
};
let runtime_type = self.gen_runtime_type(&name);

let clone_or_copy = if self.is_blittable() {
quote! {
Expand Down Expand Up @@ -459,8 +448,26 @@ impl Struct {
}
}

fn gen_runtime_type(&self, name: &Ident) -> TokenStream {
if self.0.is_winrt() {
let signature = Literal::byte_string(&self.type_signature().as_bytes());

quote! {
unsafe impl ::windows::RuntimeType for #name {
type DefaultType = Self;
const SIGNATURE: ::windows::ConstBuffer = ::windows::ConstBuffer::from_slice(#signature);
}
}
} else {
TokenStream::new()
}
}

fn gen_replacement(&self) -> Option<TokenStream> {
match self.0.full_name() {
("Windows.Foundation", "DateTime") => {
Some(gen_datetime(self.gen_runtime_type(&Ident::new("DateTime"))))
}
("Windows.Win32.System.SystemServices", "BOOL") => Some(gen_bool32()),
("Windows.Win32.System.SystemServices", "PWSTR") => Some(gen_pwstr()),
("Windows.Win32.System.SystemServices", "PSTR") => Some(gen_pstr()),
Expand Down
40 changes: 40 additions & 0 deletions tests/winrt/tests/date_time.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
use std::time::{SystemTime, UNIX_EPOCH};
// use test_winrt::TestComponent::TestRunner;
use test_winrt::Windows::Foundation::{DateTime, IPropertyValue, PropertyValue};
use windows::Interface;

#[test]
fn conversion() -> windows::Result<()> {
// TODO: imitate time_span.rs
// let a: DateTime = UNIX_EPOCH.into();
// let b = TestRunner::CreateUnixEpoch()?;
// assert_eq!(a, b);
//
// let c: SystemTime = b.into();
// assert_eq!(c, UNIX_EPOCH);

let date_time: DateTime = UNIX_EPOCH.into();
let system_time: SystemTime = date_time.into();
assert!(system_time == UNIX_EPOCH);

Ok(())
}

#[test]
fn system_time_param() -> windows::Result<()> {
let object = PropertyValue::CreateDateTime(UNIX_EPOCH)?;
let pv: IPropertyValue = object.cast()?;
assert!(pv.GetDateTime()? == UNIX_EPOCH.into());

Ok(())
}

#[test]
fn date_time_param() -> windows::Result<()> {
// TODO: imitate time_span.rs
// let object = PropertyValue::CreateDateTime(TestRunner::CreateUnixEpoch()?)?;
// let pv: IPropertyValue = object.cast()?;
// assert!(pv.GetDateTime()? == UNIX_EPOCH.into());

Ok(())
}