1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#![doc = include_str!("../README.md")]


use std::mem;

pub trait SubsliceOffset {
    /// Returns the byte offset of an inner slice relative to an enclosing outer slice.
    ///
    /// # Examples
    ///
    /// ```
    /// let string = "a\nb\nc";
    /// let lines: Vec<&str> = string.lines().collect();
    /// assert_eq!(string.subslice_offset(lines[0]), Some(0)); // &"a"
    /// assert_eq!(string.subslice_offset(lines[1]), Some(2)); // &"b"
    /// assert_eq!(string.subslice_offset(lines[2]), Some(4)); // &"c"
    /// assert_eq!(string.subslice_offset("other!"), None);
    /// ```
    fn subslice_offset<'a>(&'a self, inner: &'a Self) -> Option<usize>;
}

impl SubsliceOffset for str {
    fn subslice_offset<'a>(&'a self, inner: &'a Self) -> Option<usize> {
        let outer = self.as_ptr() as usize;
        let inner = inner.as_ptr() as usize;
        if inner < outer || inner > outer.wrapping_add(self.len()) {
            None
        } else {
            Some(inner.wrapping_sub(outer))
        }
    }
}

impl<T> SubsliceOffset for [T] {
    fn subslice_offset<'a>(&'a self, inner: &'a Self) -> Option<usize> {
        let outer = self.as_ptr_range().start as usize..self.as_ptr_range().end as usize;
        let inner_start = inner.as_ptr_range().start as usize;
        if inner_start < outer.start || inner_start > outer.end {
            None
        } else {
            Some(inner_start.wrapping_sub(outer.start) / mem::size_of::<T>())
        }
    }
}