1use core::fmt::Debug;
8use core::ops::{Deref, Range};
9
10#[allow(clippy::len_without_is_empty)]
21pub trait Source {
22 type Slice<'a>: PartialEq + Eq + Debug
24 where
25 Self: 'a;
26
27 fn len(&self) -> usize;
29
30 fn read<'a, Chunk>(&'a self, offset: usize) -> Option<Chunk>
48 where
49 Chunk: self::Chunk<'a>;
50
51 fn slice(&self, range: Range<usize>) -> Option<Self::Slice<'_>>;
61
62 #[cfg(not(feature = "forbid_unsafe"))]
79 unsafe fn slice_unchecked(&self, range: Range<usize>) -> Self::Slice<'_>;
80
81 #[inline]
86 fn find_boundary(&self, index: usize) -> usize {
87 index
88 }
89
90 fn is_boundary(&self, index: usize) -> bool;
95}
96
97impl Source for str {
98 type Slice<'a> = &'a str;
99
100 #[inline]
101 fn len(&self) -> usize {
102 self.len()
103 }
104
105 #[inline]
106 fn read<'a, Chunk>(&'a self, offset: usize) -> Option<Chunk>
107 where
108 Chunk: self::Chunk<'a>,
109 {
110 #[cfg(not(feature = "forbid_unsafe"))]
111 if offset + (Chunk::SIZE - 1) < self.len() {
112 Some(unsafe { Chunk::from_ptr(self.as_ptr().add(offset)) })
114 } else {
115 None
116 }
117
118 #[cfg(feature = "forbid_unsafe")]
119 Chunk::from_slice(self.as_bytes().slice(offset..Chunk::SIZE + offset)?)
120 }
121
122 #[inline]
123 fn slice(&self, range: Range<usize>) -> Option<&str> {
124 self.get(range)
125 }
126
127 #[cfg(not(feature = "forbid_unsafe"))]
128 #[inline]
129 unsafe fn slice_unchecked(&self, range: Range<usize>) -> &str {
130 debug_assert!(
131 range.start <= self.len() && range.end <= self.len(),
132 "Reading out of bounds {:?} for {}!",
133 range,
134 self.len()
135 );
136
137 self.get_unchecked(range)
138 }
139
140 #[inline]
141 fn find_boundary(&self, mut index: usize) -> usize {
142 while !self.is_char_boundary(index) {
143 index += 1;
144 }
145
146 index
147 }
148
149 #[inline]
150 fn is_boundary(&self, index: usize) -> bool {
151 self.is_char_boundary(index)
152 }
153}
154
155impl Source for [u8] {
156 type Slice<'a> = &'a [u8];
157
158 #[inline]
159 fn len(&self) -> usize {
160 self.len()
161 }
162
163 #[inline]
164 fn read<'a, Chunk>(&'a self, offset: usize) -> Option<Chunk>
165 where
166 Chunk: self::Chunk<'a>,
167 {
168 #[cfg(not(feature = "forbid_unsafe"))]
169 if offset + (Chunk::SIZE - 1) < self.len() {
170 Some(unsafe { Chunk::from_ptr(self.as_ptr().add(offset)) })
171 } else {
172 None
173 }
174
175 #[cfg(feature = "forbid_unsafe")]
176 Chunk::from_slice(self.slice(offset..Chunk::SIZE + offset)?)
177 }
178
179 #[inline]
180 fn slice(&self, range: Range<usize>) -> Option<&[u8]> {
181 self.get(range)
182 }
183
184 #[cfg(not(feature = "forbid_unsafe"))]
185 #[inline]
186 unsafe fn slice_unchecked(&self, range: Range<usize>) -> &[u8] {
187 debug_assert!(
188 range.start <= self.len() && range.end <= self.len(),
189 "Reading out of bounds {:?} for {}!",
190 range,
191 self.len()
192 );
193
194 self.get_unchecked(range)
195 }
196
197 #[inline]
198 fn is_boundary(&self, index: usize) -> bool {
199 index <= self.len()
200 }
201}
202
203impl<T> Source for T
204where
205 T: Deref,
206 <T as Deref>::Target: Source,
207{
208 type Slice<'a>
209 = <T::Target as Source>::Slice<'a>
210 where
211 T: 'a;
212
213 fn len(&self) -> usize {
214 self.deref().len()
215 }
216
217 fn read<'a, Chunk>(&'a self, offset: usize) -> Option<Chunk>
218 where
219 Chunk: self::Chunk<'a>,
220 {
221 self.deref().read(offset)
222 }
223
224 fn slice(&self, range: Range<usize>) -> Option<Self::Slice<'_>> {
225 self.deref().slice(range)
226 }
227
228 #[cfg(not(feature = "forbid_unsafe"))]
229 unsafe fn slice_unchecked(&self, range: Range<usize>) -> Self::Slice<'_> {
230 self.deref().slice_unchecked(range)
231 }
232
233 fn is_boundary(&self, index: usize) -> bool {
234 self.deref().is_boundary(index)
235 }
236
237 fn find_boundary(&self, index: usize) -> usize {
238 self.deref().find_boundary(index)
239 }
240}
241
242pub trait Chunk<'source>: Sized + Copy + PartialEq + Eq {
246 const SIZE: usize;
248
249 #[cfg(not(feature = "forbid_unsafe"))]
255 unsafe fn from_ptr(ptr: *const u8) -> Self;
256
257 #[cfg(feature = "forbid_unsafe")]
260 fn from_slice(s: &'source [u8]) -> Option<Self>;
261}
262
263#[allow(clippy::needless_lifetimes)]
264impl<'source> Chunk<'source> for u8 {
265 const SIZE: usize = 1;
266
267 #[inline]
268 #[cfg(not(feature = "forbid_unsafe"))]
269 unsafe fn from_ptr(ptr: *const u8) -> Self {
270 *ptr
271 }
272
273 #[inline]
274 #[cfg(feature = "forbid_unsafe")]
275 fn from_slice(s: &'source [u8]) -> Option<Self> {
276 s.first().copied()
277 }
278}
279
280impl<'source, const N: usize> Chunk<'source> for &'source [u8; N] {
281 const SIZE: usize = N;
282
283 #[inline]
284 #[cfg(not(feature = "forbid_unsafe"))]
285 unsafe fn from_ptr(ptr: *const u8) -> Self {
286 &*(ptr as *const [u8; N])
287 }
288
289 #[inline]
290 #[cfg(feature = "forbid_unsafe")]
291 fn from_slice(s: &'source [u8]) -> Option<Self> {
292 s.slice(0..Self::SIZE).and_then(|x| x.try_into().ok())
293 }
294}