-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
Instant::checked_duration_since #58395
Conversation
r? @dtolnay (rust_highfive has picked a reviewer for you, use r? to override) |
This comment has been minimized.
This comment has been minimized.
e9d7aa3
to
150a0f3
Compare
This comment has been minimized.
This comment has been minimized.
150a0f3
to
6f40163
Compare
This comment has been minimized.
This comment has been minimized.
cc #58402 |
6f40163
to
68244f4
Compare
This comment has been minimized.
This comment has been minimized.
How tests are supposed to be added for fresh |
@vi You add |
68244f4
to
7b2a08c
Compare
The job Click to expand the log.
I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact |
/// # Examples | ||
/// | ||
/// ```no_run | ||
/// use std::time::{Duration, Instant}; |
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.
/// use std::time::{Duration, Instant}; | |
/// #![feature(checked_duration_since)] | |
/// use std::time::{Duration, Instant}; |
src/libstd/time.rs
Outdated
#[test] | ||
fn checked_instant_duration_nopanic() { | ||
let a = Instant::now(); | ||
(a - Duration::new(1, 0)).checked_duration_since(a); |
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.
nit: probably worth checking that it's None, too.
Random thought: would |
@scottmcm I was also thinking about returning Another idea, for laziers who don't want to remember which one is earlier and which one is later: /// Returns the amount of time elapsed from another instant to this one,
/// or from this one to another one, whichever is non-negative.
pub fn distance(&self, another: Instant) -> Duration; I'll probably add Is wrong order of |
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.
Could you explain more about the concrete use case for this? The usual use of Instant is for measuring duration between a "start" and "end" instant, in which you always know which one is first.
I think #55527 was well justified:
Since
SystemTime
is opaque there is no way to check if the result of an addition will be in bounds. That makes theAdd<Duration>
trait completely unusable with untrusted data. This is a big problem because adding aDuration
toUNIX_EPOCH
is the standard way of constructing aSystemTime
from a unix timestamp.
but there doesn't seem to be a similar compelling justification in #58402.
I agree that these are things we could add, but I would prefer not to pack the standard library with public signatures that will only ever get called by the test suite of the standard library. I would like for anything we add to be justified more strongly than this. |
@dtolnay, The reason is similar to Plain For example, in some experiment spanning both local and remote host, there may be multiple |
Hmm, I am still not seeing it. What I question is not whether it's possible to provoke a panic from duration_since, but whether there would ever be code that is expressed most clearly using checked_duration_since / saturating_duration_since rather than some other way. Would you personally want to use either of these methods today in existing code if they were available and stable? Separately, would you be able to point out some existing real-world code where these methods are the clearest solution? |
Most recent example from my code:
The comparison was added when I suddenly encountered a panic. A close call nearby:
Although readable as is, using That comparison is easy to miss, leading to panic when under load. Seeing checked/saturating analogues nearby in documentation puts one in "here be Searching Github for Other code I found uses |
From your code: let now = Instant::now();
if now > deadline {
break;
}
let s: u64 = /* untrusted */;
let ns: u32 = /* untrusted */;
let since_base = Duration::new(s, ns);
let send_time = time_base + since_base;
let rtt4 = if now >= send_time { now - send_time } else { Duration::from_secs(999) }; This wouldn't be entirely fixed by checked_duration_since because the let s = Duration::from_secs(/* untrusted */);
let ns = Duration::from_nanos(/* untrusted */);
let to_send = s.checked_add(ns).unwrap_or(...);
let to_now = now - time_base;
let rtt4 = to_now.checked_sub(to_send).unwrap_or(...); Maybe this suggests a best practice of sticking as much as possible to Thanks for the example use case -- I can see from this code that Instant could benefit from a carefully designed checked API. I think there is also room for a crate called use easytime::{Duration, Instant};
let s: u64 = /* untrusted */;
let ns: u32 = /* untrusted */;
let since_base = Duration::new(s, ns);
let rtt4 = now - (time_base + since_base);
// some method to go from easytime::Duration to std::time::Duration:
let rtt4 = rtt4.unwrap_or(...); |
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.
I think these methods are good. Sorry for giving you grief! I copied your rationale over to the tracking issue.
I would still be interested in seeing an easytime crate to make this stuff easier to write correctly.
@bors r+ |
📌 Commit 91f67fd has been approved by |
I want to reason in terms of moments of time and timespans. Although it is obviously possible to use |
Hmm, we have |
Instant::checked_duration_since
Rollup of 19 pull requests Successful merges: - #57929 (Rustdoc remove old style files) - #57981 (Fix #57730) - #58074 (Stabilize slice_sort_by_cached_key) - #58196 (Add specific feature gate error for const-unstable features) - #58293 (Remove code for updating copyright years in generate-deriving-span-tests) - #58306 (Don't default on std crate when manipulating browser history) - #58359 (librustc_mir: use ? in impl_snapshot_for! macro) - #58395 (Instant::checked_duration_since) - #58429 (fix Box::into_unique effecitvely transmuting to a raw ptr) - #58433 (Update which libcore/liballoc tests Miri ignores, and document why) - #58438 (Use posix_spawn_file_actions_addchdir_np when possible) - #58440 (Whitelist the ARM v6 target-feature) - #58448 (rustdoc: mask `compiler_builtins` docs) - #58468 (split MaybeUninit into several features, expand docs a bit) - #58477 (Fix the syntax error in publish_toolstate.py) - #58479 (compile-pass test for #53606) - #58489 (Fix runtime error in generate-keyword-tests) - #58496 (Fix documentation for std::path::PathBuf::pop) - #58509 (Notify myself when Clippy toolstate changes)
Instant::checked_duration_since
Rollup of 19 pull requests Successful merges: - #57929 (Rustdoc remove old style files) - #57981 (Fix #57730) - #58074 (Stabilize slice_sort_by_cached_key) - #58196 (Add specific feature gate error for const-unstable features) - #58293 (Remove code for updating copyright years in generate-deriving-span-tests) - #58306 (Don't default on std crate when manipulating browser history) - #58359 (librustc_mir: use ? in impl_snapshot_for! macro) - #58395 (Instant::checked_duration_since) - #58429 (fix Box::into_unique effecitvely transmuting to a raw ptr) - #58433 (Update which libcore/liballoc tests Miri ignores, and document why) - #58438 (Use posix_spawn_file_actions_addchdir_np when possible) - #58440 (Whitelist the ARM v6 target-feature) - #58448 (rustdoc: mask `compiler_builtins` docs) - #58468 (split MaybeUninit into several features, expand docs a bit) - #58479 (compile-pass test for #53606) - #58489 (Fix runtime error in generate-keyword-tests) - #58496 (Fix documentation for std::path::PathBuf::pop) - #58509 (Notify myself when Clippy toolstate changes) - #58521 (Fix tracking issue for error iterators)
I think it would be less good than https://github.com/taiki-e/easytime. I think construction of // not panic-free
let _ = Checked::new(Duration::new(s, ns));
// weird and not panic-free
let _ = Checked(Some(Duration::new(s, ns)));
// :( less important words up front
let _ = Checked::new_duration(s, ns);
// ???
let _ = Checked::now();
let _ = Checked::<Instant>::now();
let _ = Checked::now_instant();
let _ = Checked::instant_now();
// fine...
// except people would write Checked::new(s, ns)
// which is confusing and breaks when we later add `new` method for another type
let _ = Checked::<Duration>::new(s, ns);
// checked_ prefix implies it returns Option, not Checked<Duration>
let _ = Duration::checked_new(s, ns);
// not bad...
let _ = Duration::new_checked(s, ns);
// ... but for Instant?
let _ = Instant::now_checked(); // ???
// easytime
let _ = Duration::new(s, ns);
let _ = Instant::now(); |
No description provided.