Repository navigation
Add std::chrono::time_point constructor overloads and tests #50
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,149 @@ | ||||||
| //! C++ overloads tests for [std::chrono::time_point][time_point] | ||||||
| //! | ||||||
| //! This file tests three constructors that can be represented in Rust. | ||||||
| //! | ||||||
| //! ### Limitations | ||||||
| //! | ||||||
| //! C++ time points use clock and duration types. | ||||||
| //! This test uses fixed types instead of supporting all possible types. | ||||||
| //! | ||||||
| //! [time_point]: https://en.cppreference.com/cpp/chrono/time_point | ||||||
|
|
||||||
| #![allow(unused_braces, reason = "Generated by overload! macro")] | ||||||
|
|
||||||
| use cpp::cpp; | ||||||
| use splat_overload::overload; | ||||||
| use std::ffi::{c_longlong, c_void}; | ||||||
| use std::marker::PhantomData; | ||||||
|
|
||||||
| cpp! {{ | ||||||
| #include <chrono> | ||||||
|
|
||||||
| using TestClock = std::chrono::system_clock; | ||||||
| using TestDuration = std::chrono::milliseconds; | ||||||
| using TestTimePoint = | ||||||
| std::chrono::time_point<TestClock, TestDuration>; | ||||||
|
|
||||||
| using TestSecondsTimePoint = | ||||||
| std::chrono::time_point<TestClock, std::chrono::seconds>; | ||||||
| }} | ||||||
|
|
||||||
| /// A wrapper around a C++ time point with millisecond precision. | ||||||
| #[cfg_attr(not(test), expect(dead_code, reason = "Only used in tests"))] | ||||||
| pub struct StdTimePoint(*mut c_void, PhantomData<()>); | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As above, hiding the units makes the type error-prone to use.
Suggested change
|
||||||
|
|
||||||
| /// A Wrapper around a C++ time point with second precision. | ||||||
| #[cfg_attr(not(test), expect(dead_code, reason = "Only used in tests"))] | ||||||
| pub struct StdSecondsTimePoint(*mut c_void, PhantomData<()>); | ||||||
|
|
||||||
| #[cfg_attr(not(test), expect(dead_code, reason = "Only used in tests"))] | ||||||
| impl StdSecondsTimePoint { | ||||||
| /// Construct a time point from seconds since the epoch. | ||||||
| fn from_seconds(seconds: i64) -> Self { | ||||||
|
teor2345 marked this conversation as resolved.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The Please make this change throughout this file. |
||||||
| let point = unsafe { | ||||||
| cpp!([seconds as "long long"] -> *mut c_void as | ||||||
| "TestSecondsTimePoint*" { | ||||||
| return new TestSecondsTimePoint( | ||||||
| std::chrono::seconds(seconds) | ||||||
| ); | ||||||
| }) | ||||||
| }; | ||||||
|
|
||||||
| Self(point, PhantomData) | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| #[cfg_attr(not(test), expect(dead_code, reason = "Only used in tests"))] | ||||||
| impl StdTimePoint { | ||||||
| /// Construct a time point at the clock's epoch. | ||||||
| fn default() -> Self { | ||||||
| let point = unsafe { | ||||||
| cpp!([] -> *mut c_void as "TestTimePoint*" { | ||||||
| return new TestTimePoint(); | ||||||
| }) | ||||||
| }; | ||||||
|
|
||||||
| Self(point, PhantomData) | ||||||
| } | ||||||
|
|
||||||
| /// Construct a time point from milliseconds since the epoch. | ||||||
| fn from_duration(milliseconds: i64) -> Self { | ||||||
| let point = unsafe { | ||||||
| cpp!([milliseconds as "long long"] -> *mut c_void as | ||||||
| "TestTimePoint*" { | ||||||
| return new TestTimePoint( | ||||||
| TestDuration(milliseconds) | ||||||
| ); | ||||||
| }) | ||||||
| }; | ||||||
|
|
||||||
| Self(point, PhantomData) | ||||||
| } | ||||||
|
|
||||||
| /// Construct a millisecond time point from second time point. | ||||||
| fn from_other(other: &StdSecondsTimePoint) -> Self { | ||||||
| let other = other.0 as *const c_void; | ||||||
|
|
||||||
| let point = unsafe { | ||||||
| cpp!([other as "const TestSecondsTimePoint*"] -> *mut | ||||||
| c_void as "TestTimePoint*" { | ||||||
| return new TestTimePoint(*other); | ||||||
|
|
||||||
| }) | ||||||
| }; | ||||||
|
|
||||||
| Self(point, PhantomData) | ||||||
| } | ||||||
|
|
||||||
| /// Return the number of milliseconds since epoch. | ||||||
| fn milliseconds_since_epoch(&self) -> i64 { | ||||||
| let point = self.0 as *const c_void; | ||||||
|
|
||||||
| unsafe { | ||||||
| cpp!([point as "const TestTimePoint*"] -> c_longlong as | ||||||
| "long long" { | ||||||
| return point->time_since_epoch().count(); | ||||||
| }) | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| // ### Ergonomics | ||||||
| // C++ allows constructors with the same name but different arguments. | ||||||
| // | ||||||
| // Rust does not normallly support constructor overloading. | ||||||
| // The overload! macro allows these constructors to share the name new. | ||||||
| overload! { | ||||||
| impl StdTimePoint { | ||||||
| /// Construct time point at clock's epoch. | ||||||
| pub fn new() -> StdTimePoint { | ||||||
| StdTimePoint::default() | ||||||
| } | ||||||
|
|
||||||
| /// Construct time point from milliseconds since the epoch. | ||||||
| pub fn new(milliseconds: i64) -> StdTimePoint { | ||||||
| StdTimePoint::from_duration(milliseconds) | ||||||
| } | ||||||
|
|
||||||
| /// Construct time point from seconds-resolution time point. | ||||||
| pub fn new(other: &StdSecondsTimePoint) -> StdTimePoint { | ||||||
| StdTimePoint::from_other(other) | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| #[test] | ||||||
| fn test_time_point_constructors() { | ||||||
| // Test the default constructor. | ||||||
| let epoch = StdTimePoint::new(); | ||||||
| assert_eq!(epoch.milliseconds_since_epoch(), 0); | ||||||
|
|
||||||
| // Test the duration constructor. | ||||||
| let milliseconds = StdTimePoint::new(1500_i64); | ||||||
| assert_eq!(milliseconds.milliseconds_since_epoch(), 1500); | ||||||
|
|
||||||
| // Test the converting constructor. | ||||||
| let seconds = StdSecondsTimePoint::from_seconds(2); | ||||||
| let converted = StdTimePoint::new(&seconds); | ||||||
| assert_eq!(converted.milliseconds_since_epoch(), 2000); | ||||||
| } | ||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This specific type alias makes the code harder to read, because it hides that the type is milliseconds.
Instead, delete this alias, and use the milliseconds type directly.
Please also rename
TestTimePointso it is clear it is in milliseconds.