Non panicking version of &buf[start..end]


#1

Hello,

To my knowledge there is no non-panicking equivalent of &buf[start..end] in the stdlib. Have I got this right? Would this be considered as a PR?

I asked on IRC and the first response turned out to have 2 bugs, which I guess is a datapoint in having it included in the stdlib: https://botbot.me/mozilla/rust/2015-09-21/?msg=50158708&page=10

(I wanted this today because I need to add some experimental code to an existing production process which cannot afford to fail. I want to reduce the chance of panicing in the new experimental code as much as possible.)

Thanks,

Phil


#2

Should it return an Option<&[T]>? A slice with the available elements? Or a Result<&[T], &[T]> (where the error part is the available elements on overflow)?


#3

I think it would be a good thing to have. We’re kind of working on adding it to odds.


#4

In my limited experience these things are usually an error, e.g. some index arithmetic which can blow up in a way you hadn’t thought of, maybe because of a subsequent change.

In this case I’d probably want a Result<&[T], SliceError> so that I can take advantage of try!()


#5

I tried doing so with the Index trait, but it requires returning &Self::Output, so it cannot return a Result, but a &Result, which won’t work here. So, I implemented an example without the trait, requiring a method call instead, like arr.slice(0..5).

enum SliceError {
    StartOutOfBounds,
    EndOutOfBounds,
    StartBiggerThanEnd
}

struct Wrap<'a, T: 'a>(&'a [T]);
impl<'a, T> Wrap<'a, T> {
    fn slice(&self, range: Range<usize>) -> Result<&[T], SliceError> {
        if range.start >= self.0.len() {
            Err(SliceError::StartOutOfBounds)
        } else if range.end > self.0.len() {
            Err(SliceError::EndOutOfBounds)
        } else if range.start > range.end {
            Err(SliceError::StartBiggerThanEnd)
        } else {
            unsafe {
                Ok(slice::from_raw_parts (
                    self.0.as_ptr().offset(range.start as isize),
                    range.end - range.start
                ))
            }
        }
    }
}

playground