Skip to content

Commit 2c8c3ad

Browse files
committed
Merge branch 'master' of github.com:rust-lang/rfcs
2 parents 19da8c4 + 27fcfc0 commit 2c8c3ad

File tree

2 files changed

+224
-0
lines changed

2 files changed

+224
-0
lines changed

text/1640-duration-checked-sub.md

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
- Feature Name: `duration_checked`
2+
- Start Date: 2016-06-04
3+
- RFC PR: [rust-lang/rfcs#1640](https://github.com/rust-lang/rfcs/pull/1640)
4+
- Rust Issue: [rust-lang/rust#35774](https://github.com/rust-lang/rust/issues/35774)
5+
6+
# Summary
7+
[summary]: #summary
8+
9+
This RFC adds the `checked_*` methods already known from primitives like
10+
`usize` to `Duration`.
11+
12+
# Motivation
13+
[motivation]: #motivation
14+
15+
Generally this helps when subtracting `Duration`s which can be the case quite
16+
often.
17+
18+
One abstract example would be executing a specific piece of code repeatedly
19+
after a constant amount of time.
20+
21+
Specific examples would be a network service or a rendering process emitting a
22+
constant amount of frames per second.
23+
24+
Example code would be as follows:
25+
26+
```rust
27+
28+
// This function is called repeatedly
29+
fn render() {
30+
// 10ms delay results in 100 frames per second
31+
let wait_time = Duration::from_millis(10);
32+
33+
// `Instant` for elapsed time
34+
let start = Instant::now();
35+
36+
// execute code here
37+
render_and_output_frame();
38+
39+
// there are no negative `Duration`s so this does nothing if the elapsed
40+
// time is longer than the defined `wait_time`
41+
start.elapsed().checked_sub(wait_time).and_then(std::thread::sleep);
42+
}
43+
```
44+
45+
Of course it is also suitable to not introduce `panic!()`s when adding
46+
`Duration`s.
47+
48+
# Detailed design
49+
[design]: #detailed-design
50+
51+
The detailed design would be exactly as the current `sub()` method, just
52+
returning an `Option<Duration>` and passing possible `None` values from the
53+
underlying primitive types:
54+
55+
```rust
56+
impl Duration {
57+
fn checked_sub(self, rhs: Duration) -> Option<Duration> {
58+
if let Some(mut secs) = self.secs.checked_sub(rhs.secs) {
59+
let nanos = if self.nanos >= rhs.nanos {
60+
self.nanos - rhs.nanos
61+
} else {
62+
if let Some(secs) = secs.checked_sub(1) {
63+
self.nanos + NANOS_PER_SEC - rhs.nanos
64+
}
65+
else {
66+
return None;
67+
}
68+
};
69+
debug_assert!(nanos < NANOS_PER_SEC);
70+
Some(Duration { secs: secs, nanos: nanos })
71+
}
72+
else {
73+
None
74+
}
75+
}
76+
}
77+
```
78+
79+
The same accounts for all other added methods, namely:
80+
81+
- `checked_add()`
82+
- `checked_sub()`
83+
- `checked_mul()`
84+
- `checked_div()`
85+
86+
# Drawbacks
87+
[drawbacks]: #drawbacks
88+
89+
`None`.
90+
91+
# Alternatives
92+
[alternatives]: #alternatives
93+
94+
The alternatives are simply not doing this and forcing the programmer to code
95+
the check on their behalf.
96+
This is not what you want.
97+
98+
# Unresolved questions
99+
[unresolved]: #unresolved-questions
100+
101+
`None`.
102+

text/1679-panic-safe-slicing.md

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
- Feature Name: `panic_safe_slicing`
2+
- Start Date: 2015-10-16
3+
- RFC PR: [rust-lang/rfcs#1679](https://github.com/rust-lang/rfcs/pull/1679)
4+
- Rust Issue: [rust-lang/rfcs#35729](https://github.com/rust-lang/rust/issues/35729)
5+
6+
# Summary
7+
8+
Add "panic-safe" or "total" alternatives to the existing panicking indexing syntax.
9+
10+
# Motivation
11+
12+
`SliceExt::get` and `SliceExt::get_mut` can be thought as non-panicking versions of the simple
13+
indexing syntax, `a[idx]`, and `SliceExt::get_unchecked` and `SliceExt::get_unchecked_mut` can
14+
be thought of as unsafe versions with bounds checks elided. However, there is no such equivalent for
15+
`a[start..end]`, `a[start..]`, or `a[..end]`. This RFC proposes such methods to fill the gap.
16+
17+
# Detailed design
18+
19+
The `get`, `get_mut`, `get_unchecked`, and `get_unchecked_mut` will be made generic over `usize`
20+
as well as ranges of `usize` like slice's `Index` implementation currently is. This will allow e.g.
21+
`a.get(start..end)` which will behave analagously to `a[start..end]`.
22+
23+
Because methods cannot be overloaded in an ad-hoc manner in the same way that traits may be
24+
implemented, we introduce a `SliceIndex` trait which is implemented by types which can index into a
25+
slice:
26+
```rust
27+
pub trait SliceIndex<T> {
28+
type Output: ?Sized;
29+
30+
fn get(self, slice: &[T]) -> Option<&Self::Output>;
31+
fn get_mut(self, slice: &mut [T]) -> Option<&mut Self::Output>;
32+
unsafe fn get_unchecked(self, slice: &[T]) -> &Self::Output;
33+
unsafe fn get_mut_unchecked(self, slice: &[T]) -> &mut Self::Output;
34+
fn index(self, slice: &[T]) -> &Self::Output;
35+
fn index_mut(self, slice: &mut [T]) -> &mut Self::Output;
36+
}
37+
38+
impl<T> SliceIndex<T> for usize {
39+
type Output = T;
40+
// ...
41+
}
42+
43+
impl<T, R> SliceIndex<T> for R
44+
where R: RangeArgument<usize>
45+
{
46+
type Output = [T];
47+
// ...
48+
}
49+
```
50+
51+
And then alter the `Index`, `IndexMut`, `get`, `get_mut`, `get_unchecked`, and `get_mut_unchecked`
52+
implementations to be generic over `SliceIndex`:
53+
```rust
54+
impl<T> [T] {
55+
pub fn get<I>(&self, idx: I) -> Option<I::Output>
56+
where I: SliceIndex<T>
57+
{
58+
idx.get(self)
59+
}
60+
61+
pub fn get_mut<I>(&mut self, idx: I) -> Option<I::Output>
62+
where I: SliceIndex<T>
63+
{
64+
idx.get_mut(self)
65+
}
66+
67+
pub unsafe fn get_unchecked<I>(&self, idx: I) -> I::Output
68+
where I: SliceIndex<T>
69+
{
70+
idx.get_unchecked(self)
71+
}
72+
73+
pub unsafe fn get_mut_unchecked<I>(&mut self, idx: I) -> I::Output
74+
where I: SliceIndex<T>
75+
{
76+
idx.get_mut_unchecked(self)
77+
}
78+
}
79+
80+
impl<T, I> Index<I> for [T]
81+
where I: SliceIndex<T>
82+
{
83+
type Output = I::Output;
84+
85+
fn index(&self, idx: I) -> &I::Output {
86+
idx.index(self)
87+
}
88+
}
89+
90+
impl<T, I> IndexMut<I> for [T]
91+
where I: SliceIndex<T>
92+
{
93+
fn index_mut(&self, idx: I) -> &mut I::Output {
94+
idx.index_mut(self)
95+
}
96+
}
97+
```
98+
99+
# Drawbacks
100+
101+
- The `SliceIndex` trait is unfortunate - it's tuned for exactly the set of methods it's used by.
102+
It only exists because inherent methods cannot be overloaded the same way that trait
103+
implementations can be. It would most likely remain unstable indefinitely.
104+
- Documentation may suffer. Rustdoc output currently explicitly shows each of the ways you can
105+
index a slice, while there will simply be a single generic implementation with this change. This
106+
may not be that bad, though. The doc block currently seems to provided the most valuable
107+
information to newcomers rather than the trait bound, and that will still be present with this
108+
change.
109+
110+
# Alternatives
111+
112+
- Stay as is.
113+
- A previous version of this RFC introduced new `get_slice` etc methods rather than overloading
114+
`get` etc. This avoids the utility trait but is somewhat less ergonomic.
115+
- Instead of one trait amalgamating all of the required methods, we could have one trait per
116+
method. This would open a more reasonable door to stabilizing those traits, but adds quite a lot
117+
more surface area. Replacing an unstable `SliceIndex` trait with a collection would be
118+
backwards compatible.
119+
120+
# Unresolved questions
121+
122+
None

0 commit comments

Comments
 (0)