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// }