From 5b0e31a1da84b7587a242c7ded89840a18b6eb65 Mon Sep 17 00:00:00 2001 From: Barosl Lee Date: Fri, 16 Oct 2015 14:40:23 +0900 Subject: [PATCH] Add the text --- text/0000-panic-safe-slicing.md | 89 +++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 text/0000-panic-safe-slicing.md diff --git a/text/0000-panic-safe-slicing.md b/text/0000-panic-safe-slicing.md new file mode 100644 index 00000000000..cfaa7c9f992 --- /dev/null +++ b/text/0000-panic-safe-slicing.md @@ -0,0 +1,89 @@ +- Feature Name: panic_safe_slicing +- Start Date: 2015-10-16 +- RFC PR: (leave this empty) +- Rust Issue: (leave this empty) + +# Summary + +Add "panic-safe" or "total" alternatives to the existing panicking slicing syntax. + +# Motivation + +`SliceExt::get` and `SliceExt::get_mut` can be thought as non-panicking versions of the simple +slicing syntax, `a[idx]`. However, there is no such equivalent for `a[start..end]`, `a[start..]`, +or `a[..end]`. This RFC proposes such methods to fill the gap. + +# Detailed design + +Add `get_range`, `get_range_mut`, `get_range_unchecked`, `get_range_unchecked_mut` to `SliceExt`. + +`get_range` and `get_range_mut` may be implemented roughly as follows: + +```rust +use std::ops::{RangeFrom, RangeTo, Range}; +use std::slice::from_raw_parts; +use core::slice::SliceExt; + +trait Rangeable { + fn start(&self, slice: &T) -> usize; + fn end(&self, slice: &T) -> usize; +} + +impl Rangeable for RangeFrom { + fn start(&self, _: &T) -> usize { self.start } + fn end(&self, slice: &T) -> usize { slice.len() } +} + +impl Rangeable for RangeTo { + fn start(&self, _: &T) -> usize { 0 } + fn end(&self, _: &T) -> usize { self.end } +} + +impl Rangeable for Range { + fn start(&self, _: &T) -> usize { self.start } + fn end(&self, _: &T) -> usize { self.end } +} + +trait GetRangeExt: SliceExt { + fn get_range>(&self, range: R) -> Option<&[Self::Item]>; +} + +impl GetRangeExt for [T] { + fn get_range>(&self, range: R) -> Option<&[T]> { + let start = range.start(self); + let end = range.end(self); + + if start > end { return None; } + if end > self.len() { return None; } + + unsafe { Some(from_raw_parts(self.as_ptr().offset(start as isize), end - start)) } + } +} + +fn main() { + let a = [1, 2, 3, 4, 5]; + + assert_eq!(a.get_range(1..), Some(&a[1..])); + assert_eq!(a.get_range(..3), Some(&a[..3])); + assert_eq!(a.get_range(2..5), Some(&a[2..5])); + assert_eq!(a.get_range(..6), None); + assert_eq!(a.get_range(4..2), None); +} +``` + +`get_range_unchecked` and `get_range_unchecked_mut` should be the unchecked versions of the methods +above. + +# Drawbacks + +- Are these methods worth adding to `std`? Are such use cases common to justify such extention? + +# Alternatives + +- Stay as is. +- Could there be any other (and better!) total functions that serve the similar purpose? + +# Unresolved questions + +- Naming, naming, naming: Is `get_range` the most suitable name? How about `get_slice`? Or any +others?