1use core::ops::Range;
2
3use crate::ptr_utils::*;
4
5#[derive(Clone, Copy, Hash)]
15pub struct Span {
16 base: *mut u8,
17 acme: *mut u8,
18}
19
20unsafe impl Send for Span {}
21
22impl Default for Span {
23 fn default() -> Self {
24 Self::empty()
25 }
26}
27
28impl core::fmt::Debug for Span {
29 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
30 f.write_fmt(format_args!("{:p}..[{}]..{:p}", self.base, self.size(), self.acme))
31 }
32}
33
34impl core::fmt::Display for Span {
35 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
36 match self.get_base_acme() {
37 Some((base, acme)) => f.write_fmt(format_args!("{:p}..{:p}", base, acme)),
38 None => f.write_str("Empty Span"),
39 }
40 }
41}
42
43impl<T> From<Range<*mut T>> for Span {
44 fn from(value: Range<*mut T>) -> Self {
45 Self { base: value.start.cast(), acme: value.end.cast() }
46 }
47}
48
49impl<T> From<Range<*const T>> for Span {
53 fn from(value: Range<*const T>) -> Self {
54 Self { base: value.start.cast_mut().cast(), acme: value.end.cast_mut().cast() }
55 }
56}
57
58impl<T> From<&mut [T]> for Span {
59 fn from(value: &mut [T]) -> Self {
60 Self::from(value.as_mut_ptr_range())
61 }
62}
63
64impl<T> From<&[T]> for Span {
68 fn from(value: &[T]) -> Self {
69 Self::from(value.as_ptr_range())
70 }
71}
72
73impl<T, const N: usize> From<&mut [T; N]> for Span {
74 fn from(value: &mut [T; N]) -> Self {
75 Self::from(value as *mut [T; N])
76 }
77}
78
79impl<T, const N: usize> From<&[T; N]> for Span {
83 fn from(value: &[T; N]) -> Self {
84 Self::from(value as *const [T; N])
85 }
86}
87
88#[cfg(feature = "nightly_api")]
89impl<T> From<*mut [T]> for Span {
90 fn from(value: *mut [T]) -> Self {
91 Self::from_slice(value)
92 }
93}
94
95#[cfg(feature = "nightly_api")]
99impl<T> From<*const [T]> for Span {
100 fn from(value: *const [T]) -> Self {
101 #[expect(deprecated)] Self::from_const_slice(value)
103 }
104}
105
106impl<T, const N: usize> From<*mut [T; N]> for Span {
107 fn from(value: *mut [T; N]) -> Self {
108 Self::from_array(value)
109 }
110}
111
112impl<T, const N: usize> From<*const [T; N]> for Span {
116 fn from(value: *const [T; N]) -> Self {
117 Self::from_array(value.cast_mut())
118 }
119}
120
121impl PartialEq for Span {
122 fn eq(&self, other: &Self) -> bool {
123 self.is_empty() && other.is_empty() || self.base == other.base && self.acme == other.acme
124 }
125}
126impl Eq for Span {}
127
128impl Span {
129 #[inline]
131 pub fn is_empty(self) -> bool {
132 self.acme <= self.base
133 }
134
135 #[inline]
137 pub fn is_sized(self) -> bool {
138 !self.is_empty()
139 }
140
141 #[inline]
143 pub fn size(self) -> usize {
144 if self.is_empty() { 0 } else { self.acme as usize - self.base as usize }
145 }
146
147 #[inline]
149 pub fn get_base_acme(self) -> Option<(*mut u8, *mut u8)> {
150 if self.is_empty() { None } else { Some((self.base, self.acme)) }
151 }
152
153 #[inline]
155 pub const fn empty() -> Self {
156 Self { base: core::ptr::null_mut(), acme: core::ptr::null_mut() }
157 }
158
159 #[inline]
161 pub const fn new(base: *mut u8, acme: *mut u8) -> Self {
162 Self { base, acme }
163 }
164
165 #[inline]
169 pub const fn from_base_size(base: *mut u8, size: usize) -> Self {
170 Self { base, acme: base.wrapping_add(size) }
171 }
172
173 #[cfg(feature = "nightly_api")]
174 #[inline]
175 pub const fn from_slice<T>(slice: *mut [T]) -> Self {
176 Self {
177 base: slice as *mut T as *mut u8,
178 acme: unsafe { (slice as *mut T).add(slice.len()).cast() },
181 }
182 }
183
184 #[deprecated = "Conversion from const references encourages UB. This will be removed in a future release."]
188 #[cfg(feature = "nightly_api")]
189 #[inline]
190 pub const fn from_const_slice<T>(slice: *const [T]) -> Self {
191 Self {
192 base: slice as *mut T as *mut u8,
193 acme: unsafe { (slice as *mut T).add(slice.len()).cast() },
196 }
197 }
198
199 #[inline]
200 pub const fn from_array<T, const N: usize>(array: *mut [T; N]) -> Self {
201 Self {
202 base: array as *mut T as *mut u8,
203 acme: unsafe { (array as *mut T).add(N).cast() },
206 }
207 }
208
209 #[deprecated = "Conversion from const references encourages UB. This will be removed in a future release."]
213 #[inline]
214 pub const fn from_const_array<T, const N: usize>(array: *const [T; N]) -> Self {
215 Self {
216 base: array as *mut T as *mut u8,
217 acme: unsafe { (array as *mut T).add(N).cast() },
220 }
221 }
222
223 #[inline]
225 pub fn to_ptr_range(self) -> Option<Range<*mut u8>> {
226 if self.is_empty() { None } else { Some(self.base..self.acme) }
227 }
228
229 #[inline]
231 pub fn to_slice(self) -> Option<*mut [u8]> {
232 if self.is_empty() {
233 None
234 } else {
235 Some(core::ptr::slice_from_raw_parts_mut(self.base, self.size()))
236 }
237 }
238
239 #[inline]
243 pub fn contains(self, ptr: *mut u8) -> bool {
244 self.base <= ptr && ptr < self.acme
246 }
247
248 #[inline]
252 pub fn contains_span(self, other: Span) -> bool {
253 other.is_empty() || self.base <= other.base && other.acme <= self.acme
254 }
255
256 #[inline]
260 pub fn overlaps(self, other: Span) -> bool {
261 self.is_sized() && other.is_sized() && !(other.base >= self.acme || self.base >= other.acme)
262 }
263
264 #[inline]
266 pub fn word_align_inward(self) -> Self {
267 if ALIGN > usize::MAX - self.base as usize {
268 Self::empty()
269 } else {
270 Self { base: align_up(self.base), acme: align_down(self.acme) }
271 }
272 }
273 #[inline]
275 pub fn word_align_outward(self) -> Self {
276 if ALIGN > usize::MAX - self.acme as usize {
277 panic!("aligning acme upward would overflow!");
278 }
279
280 Self { base: align_down(self.base), acme: align_up(self.acme) }
281 }
282
283 #[inline]
285 pub fn above(self, min: *mut u8) -> Self {
286 Self { base: if min > self.base { min } else { self.base }, acme: self.acme }
287 }
288 #[inline]
290 pub fn below(self, max: *mut u8) -> Self {
291 Self { base: self.base, acme: if max < self.acme { max } else { self.acme } }
292 }
293
294 #[inline]
299 pub fn except(self, exclude: Span) -> (Self, Self) {
300 match exclude.get_base_acme() {
301 Some((base, acme)) => (self.below(base), self.above(acme)),
302 None => (self, Span::empty()),
303 }
304 }
305
306 #[inline]
310 pub fn fit_within(self, other: Span) -> Self {
311 if other.is_empty() {
312 other
313 } else {
314 Self {
315 base: if other.base > self.base { other.base } else { self.base },
316 acme: if other.acme < self.acme { other.acme } else { self.acme },
317 }
318 }
319 }
320 #[inline]
324 pub fn fit_over(self, other: Self) -> Self {
325 if other.is_empty() {
326 self
327 } else {
328 Self {
329 base: if other.base < self.base { other.base } else { self.base },
330 acme: if other.acme > self.acme { other.acme } else { self.acme },
331 }
332 }
333 }
334
335 #[inline]
342 pub fn extend(self, low: usize, high: usize) -> Self {
343 if self.is_empty() {
344 self
345 } else {
346 assert!((self.base as usize).checked_sub(low).is_some());
347 assert!((self.acme as usize).checked_add(high).is_some());
348
349 Self { base: self.base.wrapping_sub(low), acme: self.acme.wrapping_add(high) }
350 }
351 }
352
353 #[inline]
359 pub fn truncate(self, low: usize, high: usize) -> Span {
360 if self.is_empty() {
361 self
362 } else if (self.base as usize).checked_add(low).is_none()
363 || (self.acme as usize).checked_sub(high).is_none()
364 {
365 Span::empty()
366 } else {
367 Self {
368 base: self.base.wrapping_add(low),
370 acme: self.acme.wrapping_sub(high),
371 }
372 }
373 }
374}
375
376#[cfg(test)]
377mod test {
378 use super::*;
379
380 fn ptr(addr: usize) -> *mut u8 {
381 core::ptr::null_mut::<u8>().wrapping_add(addr)
383 }
384
385 #[test]
386 fn test_span() {
387 let base = 1234usize;
388 let acme = 5678usize;
389
390 let bptr = ptr(base);
391 let aptr = ptr(acme);
392
393 let span = Span::from(bptr..aptr);
394 assert!(!span.is_empty());
395 assert!(span.size() == acme - base);
396
397 assert!(
398 span.word_align_inward()
399 == Span::new(
400 bptr.wrapping_add(ALIGN - 1)
401 .wrapping_sub(bptr.wrapping_add(ALIGN - 1) as usize & (ALIGN - 1)),
402 aptr.wrapping_sub(acme & (ALIGN - 1))
403 )
404 );
405 assert!(
406 span.word_align_outward()
407 == Span::new(
408 bptr.wrapping_sub(base & (ALIGN - 1)),
409 aptr.wrapping_add(ALIGN - 1)
410 .wrapping_sub(aptr.wrapping_add(ALIGN - 1) as usize & (ALIGN - 1))
411 )
412 );
413
414 assert_eq!(span.above(ptr(2345)), Span::new(ptr(2345), aptr));
415 assert_eq!(span.below(ptr(7890)), Span::new(bptr, aptr));
416 assert_eq!(span.below(ptr(3456)), Span::new(bptr, ptr(3456)));
417 assert_eq!(span.below(ptr(0123)), Span::empty());
418 assert_eq!(span.above(ptr(7890)), Span::empty());
419
420 assert_eq!(
421 span.except(Span::new(ptr(base + 1111), ptr(acme - 1111))),
422 (Span::new(bptr, ptr(base + 1111)), Span::new(ptr(acme - 1111), aptr))
423 );
424 assert_eq!(
425 span.except(Span::new(ptr(base + 1111), ptr(acme + 1111))),
426 (Span::new(bptr, ptr(base + 1111)), Span::empty())
427 );
428 assert_eq!(
429 span.except(Span::new(ptr(base - 1111), ptr(acme + 1111))),
430 (Span::empty(), Span::empty())
431 );
432 assert_eq!(span.except(Span::empty()), (span, Span::empty()));
433
434 assert!(span.fit_over(Span::empty()) == span);
435 assert!(span.fit_within(Span::empty()).is_empty());
436 assert!(span.fit_within(Span::new(ptr(0), ptr(10000))) == span);
437 assert!(span.fit_over(Span::new(ptr(0), ptr(10000))) == Span::new(ptr(0), ptr(10000)));
438 assert!(span.fit_within(Span::new(ptr(4000), ptr(10000))) == Span::new(ptr(4000), aptr));
439 assert!(span.fit_over(Span::new(ptr(4000), ptr(10000))) == Span::new(bptr, ptr(10000)));
440
441 assert!(span.extend(1234, 1010) == Span::new(ptr(0), ptr(5678 + 1010)));
442 assert!(span.truncate(1234, 1010) == Span::new(ptr(1234 + 1234), ptr(5678 - 1010)));
443 assert!(span.truncate(235623, 45235772).is_empty());
444 }
445}