Skip to content

Commit be5eb6f

Browse files
committed
Add the text
1 parent b8da6c7 commit be5eb6f

File tree

1 file changed

+89
-0
lines changed

1 file changed

+89
-0
lines changed

text/0000-panic-safe-slicing.md

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
- Feature Name: panic_safe_slicing
2+
- Start Date: 2015-10-16
3+
- RFC PR: (leave this empty)
4+
- Rust Issue: (leave this empty)
5+
6+
# Summary
7+
8+
Add "panic-safe" or "total" alternatives to the existing panicking slicing syntax.
9+
10+
# Motivation
11+
12+
`SliceExt::get` and `SliceExt::get_mut` can be thought as non-panicking versions of the simple
13+
slicing syntax, `a[idx]`. However, there is no such equivalent for `a[start..end]`, `a[start..]`,
14+
or `a[..end]`. This RFC proposes such methods to fill the gap.
15+
16+
# Detailed design
17+
18+
Add `get_range`, `get_range_mut`, `get_range_unchecked`, `get_range_unchecked_mut` to `SliceExt`.
19+
20+
`get_range` and `get_range_mut` may be implemented roughly as follows:
21+
22+
```rust
23+
use std::ops::{RangeFrom, RangeTo, Range};
24+
use std::slice::from_raw_parts;
25+
use core::slice::SliceExt;
26+
27+
trait Rangeable<T: ?Sized> {
28+
fn start(&self, slice: &T) -> usize;
29+
fn end(&self, slice: &T) -> usize;
30+
}
31+
32+
impl<T: SliceExt + ?Sized> Rangeable<T> for RangeFrom<usize> {
33+
fn start(&self, _: &T) -> usize { self.start }
34+
fn end(&self, slice: &T) -> usize { slice.len() }
35+
}
36+
37+
impl<T: SliceExt + ?Sized> Rangeable<T> for RangeTo<usize> {
38+
fn start(&self, _: &T) -> usize { 0 }
39+
fn end(&self, _: &T) -> usize { self.end }
40+
}
41+
42+
impl<T: SliceExt + ?Sized> Rangeable<T> for Range<usize> {
43+
fn start(&self, _: &T) -> usize { self.start }
44+
fn end(&self, _: &T) -> usize { self.end }
45+
}
46+
47+
trait GetRangeExt: SliceExt {
48+
fn get_range<R: Rangeable<Self>>(&self, range: R) -> Option<&[Self::Item]>;
49+
}
50+
51+
impl<T> GetRangeExt for [T] {
52+
fn get_range<R: Rangeable<Self>>(&self, range: R) -> Option<&[T]> {
53+
let start = range.start(self);
54+
let end = range.end(self);
55+
56+
if start > end { return None; }
57+
if end > self.len() { return None; }
58+
59+
unsafe { Some(from_raw_parts(self.as_ptr().offset(start as isize), end - start)) }
60+
}
61+
}
62+
63+
fn main() {
64+
let a = [1, 2, 3, 4, 5];
65+
66+
assert_eq!(a.get_range(1..), Some(&a[1..]));
67+
assert_eq!(a.get_range(..3), Some(&a[..3]));
68+
assert_eq!(a.get_range(2..5), Some(&a[2..5]));
69+
assert_eq!(a.get_range(..6), None);
70+
assert_eq!(a.get_range(4..2), None);
71+
}
72+
```
73+
74+
`get_range_unchecked` and `get_range_unchecked_mut` should be the unchecked versions of the methods
75+
above.
76+
77+
# Drawbacks
78+
79+
- Are these methods worth adding to `std`? Are such use cases common to justify such extention?
80+
81+
# Alternatives
82+
83+
- Stay as is.
84+
- Could there be any other (and better!) total functions that serve the similar purpose?
85+
86+
# Unresolved questions
87+
88+
- Naming, naming, naming: Is `get_range` the most suitable name? How about `get_slice`, or just
89+
`slice`? Or any others?

0 commit comments

Comments
 (0)