pcomb/
slice.rs

1//! Traits representing slices: fat pointers to a contiguous ranges of data.
2//!
3//! See the documentation of the [Slice] trait, the main trait of this module.
4
5extern crate alloc;
6use alloc::string::String;
7use core::ops::{RangeBounds, Bound};
8
9use crate::parse::Parse;
10
11
12/// A slice is a fat pointer to a contiguous range of data with fallible slicing
13/// operations.
14///
15/// The slice should be cheap or free to clone and data should be indexed in
16/// constant time. Two slices should be equal if their contents are equal.
17pub trait Slice {
18  type Output: Slice;
19
20  /// Try to subslice this slice, yielding the subslice or None on a failure.
21  ///
22  /// Slicing a 0-length `a.slice(4..4)` and slicing using [std::ops::RangeFull]
23  /// `a.slice(..)` must never fail.
24  ///
25  /// # Examples
26  /// ```
27  /// use pcomb::Slice;
28  ///
29  /// let arr = "hello world!";
30  /// assert_eq!(arr.slice(1..4), Some("ell"));
31  /// assert_eq!(arr.slice(6..), Some("world!"));
32  /// assert_eq!(arr.slice(..), Some(arr));
33  /// assert_eq!("café".slice(2..4), None);  // not on a character boundary
34  /// ```
35  fn slice<R: RangeBounds<usize>>(&self, bounds: R) -> Option<Self::Output>;
36
37  /// Determine the length of this slice. Should be a cheap or free operation.
38  ///
39  /// # Examples
40  /// ```
41  /// use pcomb::Slice;
42  ///
43  /// let arr = "hello world!";
44  /// assert_eq!(Slice::len(&arr), 12);
45  ///
46  /// let arr = &[1u32, 9, 6];
47  /// assert_eq!(Slice::len(&arr), 3);
48  /// ```
49  fn len(&self) -> usize;
50
51  /// Try to divide this slice into two non-overlapping subslices at index.
52  /// Returns None if the index is out of bounds or if slicing failed.
53  ///
54  /// The first slice will contain all values from the interval `[0, index)` and
55  /// the second from the interval `[index, len())`.
56  ///
57  /// # Examples
58  /// ```
59  /// use pcomb::Slice;
60  ///
61  /// let arr = &[1u32, 5, 3, 9, 10];
62  /// let (left, right) = Slice::split_at(&arr, 2).unwrap();
63  /// assert_eq!(left, &[1, 5]);
64  /// assert_eq!(right, &[3, 9, 10]);
65  /// ```
66  fn split_at(&self, index: usize) -> Option<(Self::Output, Self::Output)> {
67    Some((self.slice(..index)?, self.slice(index..)?))
68  }
69
70  /// Parse this slice using the given parser.
71  ///
72  /// Equivalent to `parser.parse(self)`.
73  fn parse_with<P>(self, parser: P) -> Result<(Self, P::Output), P::Err>
74  where P: Parse<Self>, Self: Sized {
75    parser.parse(self)
76  }
77}
78
79/// Internal: convert a RangeBounds into a pair of indices, given a length.
80fn into_indices<R: RangeBounds<usize>>(bounds: R, len: usize) -> (usize, usize) {
81  let start = match bounds.start_bound().cloned() {
82    Bound::Included(idx) => idx,
83    Bound::Excluded(idx) => idx + 1,
84    Bound::Unbounded => 0,
85  };
86
87  let end = match bounds.end_bound().cloned() {
88    Bound::Included(idx) => idx + 1,
89    Bound::Excluded(idx) => idx,
90    Bound::Unbounded => len,
91  };
92
93  (start, end)
94}
95
96impl Slice for &str {
97  type Output = Self;
98
99  fn slice<R: RangeBounds<usize>>(&self, bounds: R) -> Option<Self::Output> {
100    // RangeBounds does not implement SliceIndex for whatever reason
101    let (start, end) = into_indices(bounds, self.len());
102    self.get(start..end)
103  }
104
105  fn len(&self) -> usize { str::len(self) }
106}
107
108impl<'a> Slice for &'a String {
109  type Output = &'a str;
110
111  fn slice<R: RangeBounds<usize>>(&self, bounds: R) -> Option<Self::Output> {
112    // RangeBounds does not implement SliceIndex for whatever reason
113    let (start, end) = into_indices(bounds, self.len());
114    self.get(start..end)
115  }
116
117  fn len(&self) -> usize { str::len(self) }
118}
119
120impl<T> Slice for &[T] {
121  type Output = Self;
122
123  fn slice<R: RangeBounds<usize>>(&self, bounds: R) -> Option<Self::Output> {
124    self.get((bounds.start_bound().cloned(), bounds.end_bound().cloned()))
125  }
126
127  fn len(&self) -> usize { <[T]>::len(self) }
128}
129
130impl<'a, T, const N: usize> Slice for &'a [T; N] {
131  type Output = &'a [T];
132
133  fn slice<R: RangeBounds<usize>>(&self, bounds: R) -> Option<Self::Output> {
134    self.get((bounds.start_bound().cloned(), bounds.end_bound().cloned()))
135  }
136
137  fn len(&self) -> usize { N }
138}
139
140// impl<T: Read> Slice for T {
141//   type Output = &[u8];
142
143//   fn slice(&self, bounds: Range<usize>) -> Option<Self::Output> {
144//     self.
145//   }
146//   fn len(&self) -> usize { todo!() }
147// }
148
149// impl<T: BufRead> Slice for T {
150//   type Output = &[u8];
151
152//   fn slice(&self, bounds: Range<usize>) -> Option<Self::Output> {
153//     self.
154//   }
155//   fn len(&self) -> usize { todo!() }
156// }