1use core::cmp::Ordering;
2use core::fmt;
3use core::num::NonZeroUsize;
4use core::ops::{Add, Range, Sub};
5
6use align_address::{usize_align_up, usize_is_aligned_to};
7
8use crate::{PageLayout, PAGE_SIZE};
9
10#[non_exhaustive]
12#[derive(Clone, PartialEq, Eq, Debug)]
13pub struct PageRangeError;
14
15impl fmt::Display for PageRangeError {
16 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
17 f.write_str("invalid parameters to PageLayout::new")
18 }
19}
20
21#[derive(Copy, Clone, PartialEq, Eq, Hash)]
23pub struct PageRange {
24 start: usize,
25 end: NonZeroUsize,
26}
27
28impl PageRange {
29 pub const fn new(start: usize, end: usize) -> Result<Self, PageRangeError> {
46 if start >= end {
47 return Err(PageRangeError);
48 }
49
50 if !usize_is_aligned_to(start, PAGE_SIZE) {
51 return Err(PageRangeError);
52 }
53
54 if !usize_is_aligned_to(end, PAGE_SIZE) {
55 return Err(PageRangeError);
56 }
57
58 let end = match NonZeroUsize::new(end) {
59 Some(end) => end,
60 None => unreachable!(),
61 };
62
63 Ok(Self { start, end })
64 }
65
66 pub const fn from_start_len(start: usize, len: usize) -> Result<Self, PageRangeError> {
85 let end = match start.checked_add(len) {
86 Some(end) => end,
87 None => return Err(PageRangeError),
88 };
89 Self::new(start, end)
90 }
91
92 pub const fn start(self) -> usize {
103 self.start
104 }
105
106 pub const fn end(self) -> usize {
117 self.end.get()
118 }
119
120 pub const fn len(self) -> NonZeroUsize {
131 match NonZeroUsize::new(self.end() - self.start) {
132 Some(len) => len,
133 None => unreachable!(),
134 }
135 }
136
137 pub const fn pages(self) -> NonZeroUsize {
148 match NonZeroUsize::new(self.len().get() / PAGE_SIZE) {
149 Some(pages) => pages,
150 None => unreachable!(),
151 }
152 }
153
154 pub const fn overlaps(self, other: Self) -> bool {
168 self.end() > other.start && self.start < other.end()
169 }
170
171 pub const fn touches(self, other: Self) -> bool {
185 self.end() == other.start || self.start == other.end()
186 }
187
188 pub const fn contains(self, other: Self) -> bool {
200 self.start <= other.start && self.end() >= other.end()
201 }
202
203 pub const fn fit(self, layout: PageLayout) -> Option<PageRange> {
216 let start = usize_align_up(self.start, layout.align());
217 let range = match Self::from_start_len(start, layout.size()) {
218 Ok(range) => range,
219 Err(_) => unreachable!(),
220 };
221 if self.contains(range) {
222 Some(range)
223 } else {
224 None
225 }
226 }
227}
228
229impl TryFrom<Range<usize>> for PageRange {
230 type Error = PageRangeError;
231
232 fn try_from(value: Range<usize>) -> Result<Self, Self::Error> {
233 Self::new(value.start, value.end)
234 }
235}
236
237impl fmt::Debug for PageRange {
238 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
239 self.start.fmt(f)?;
240 f.write_str("..")?;
241 self.end.fmt(f)?;
242 Ok(())
243 }
244}
245
246impl fmt::Display for PageRange {
247 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
248 let Self { start, end } = self;
249 let len = self.len();
250 let pages = self.pages();
251 if f.alternate() {
252 write!(
253 f,
254 "{start:#18x}..{end:#18x} (len = {len:#18x}, pages = {pages:16})"
255 )
256 } else {
257 write!(f, "{start:#x}..{end:#x} (len = {len:#x}, pages = {pages})")
258 }
259 }
260}
261
262impl PartialOrd for PageRange {
263 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
264 if self.end() <= other.start {
265 Some(Ordering::Less)
266 } else if self.start >= other.end() {
267 Some(Ordering::Greater)
268 } else if self == other {
269 Some(Ordering::Equal)
270 } else {
271 None
272 }
273 }
274}
275
276impl Add for PageRange {
277 type Output = Option<Self>;
278
279 fn add(self, rhs: Self) -> Self::Output {
280 if !(self.touches(rhs) || self.overlaps(rhs)) {
281 return None;
282 }
283
284 Some(PageRange::new(self.start.min(rhs.start), self.end().max(rhs.end())).unwrap())
285 }
286}
287
288impl Sub for PageRange {
289 type Output = PageRangeSub;
290
291 fn sub(self, rhs: Self) -> Self::Output {
292 if !self.overlaps(rhs) {
293 return PageRangeSub::One(self);
294 }
295
296 let before = PageRange::new(self.start, rhs.start).ok();
297 let after = PageRange::new(rhs.end(), self.end()).ok();
298
299 match (before, after) {
300 (None, None) => PageRangeSub::None,
301 (None, Some(range)) | (Some(range), None) => PageRangeSub::One(range),
302 (Some(a), Some(b)) => PageRangeSub::Two(a, b),
303 }
304 }
305}
306
307pub enum PageRangeSub {
309 None,
311
312 One(PageRange),
314
315 Two(PageRange, PageRange),
317}
318
319#[cfg(test)]
320mod tests {
321 use core::alloc::Layout;
322
323 use super::*;
324
325 #[test]
326 fn niche() {
327 assert_eq!(
328 Layout::new::<Option<PageRange>>(),
329 Layout::new::<PageRange>()
330 );
331 }
332
333 #[test]
334 fn overlaps() {
335 let assert = |a, b, c: bool| {
336 let a = PageRange::try_from(a).unwrap();
337 let b = PageRange::try_from(b).unwrap();
338 assert_eq!(c, a.overlaps(b), "{a}.overlaps({b})");
339 };
340
341 assert(0x2000..0x5000, 0x0000..0x1000, false);
342 assert(0x2000..0x5000, 0x0000..0x2000, false);
343 assert(0x2000..0x5000, 0x0000..0x3000, true);
344 assert(0x2000..0x5000, 0x0000..0x4000, true);
345 assert(0x2000..0x5000, 0x0000..0x5000, true);
346 assert(0x2000..0x5000, 0x0000..0x6000, true);
347 assert(0x2000..0x5000, 0x0000..0x7000, true);
348 assert(0x2000..0x5000, 0x0000..0x7000, true);
349 assert(0x2000..0x5000, 0x1000..0x7000, true);
350 assert(0x2000..0x5000, 0x2000..0x7000, true);
351 assert(0x2000..0x5000, 0x3000..0x7000, true);
352 assert(0x2000..0x5000, 0x4000..0x7000, true);
353 assert(0x2000..0x5000, 0x5000..0x7000, false);
354 assert(0x2000..0x5000, 0x6000..0x7000, false);
355 }
356
357 #[test]
358 fn add() {
359 let assert = |a, b, c: Option<Range<usize>>| {
360 let a = PageRange::try_from(a).unwrap();
361 let b = PageRange::try_from(b).unwrap();
362 let c = c.map(|range| PageRange::try_from(range).unwrap());
363 assert_eq!(c, a + b, "{a} + {b}");
364 };
365
366 assert(0x2000..0x5000, 0x0000..0x1000, None);
367 assert(0x2000..0x5000, 0x0000..0x2000, Some(0x0000..0x5000));
368 assert(0x2000..0x5000, 0x0000..0x3000, Some(0x0000..0x5000));
369 assert(0x2000..0x5000, 0x0000..0x4000, Some(0x0000..0x5000));
370 assert(0x2000..0x5000, 0x0000..0x5000, Some(0x0000..0x5000));
371 assert(0x2000..0x5000, 0x0000..0x6000, Some(0x0000..0x6000));
372 assert(0x2000..0x5000, 0x0000..0x7000, Some(0x0000..0x7000));
373 assert(0x2000..0x5000, 0x1000..0x7000, Some(0x1000..0x7000));
374 assert(0x2000..0x5000, 0x2000..0x7000, Some(0x2000..0x7000));
375 assert(0x2000..0x5000, 0x3000..0x7000, Some(0x2000..0x7000));
376 assert(0x2000..0x5000, 0x4000..0x7000, Some(0x2000..0x7000));
377 assert(0x2000..0x5000, 0x5000..0x7000, Some(0x2000..0x7000));
378 assert(0x2000..0x5000, 0x6000..0x7000, None);
379
380 assert(0x2000..0x5000, 0x2000..0x3000, Some(0x2000..0x5000));
381 assert(0x2000..0x5000, 0x2000..0x4000, Some(0x2000..0x5000));
382 assert(0x2000..0x5000, 0x2000..0x5000, Some(0x2000..0x5000));
383 assert(0x2000..0x5000, 0x3000..0x5000, Some(0x2000..0x5000));
384 assert(0x2000..0x5000, 0x4000..0x5000, Some(0x2000..0x5000));
385
386 assert(0x2000..0x5000, 0x3000..0x4000, Some(0x2000..0x5000));
387 }
388
389 #[allow(clippy::single_range_in_vec_init)]
390 #[test]
391 fn sub() {
392 let assert = |a, b, c: &[Range<usize>]| {
393 let a = PageRange::try_from(a).unwrap();
394 let b = PageRange::try_from(b).unwrap();
395 let c = c
396 .iter()
397 .cloned()
398 .map(|range| PageRange::try_from(range).unwrap())
399 .collect::<Vec<_>>();
400 let v = match a - b {
401 PageRangeSub::None => vec![],
402 PageRangeSub::One(a) => vec![a],
403 PageRangeSub::Two(a, b) => vec![a, b],
404 };
405 assert_eq!(c, v, "{a} - {b}");
406 };
407
408 assert(0x2000..0x5000, 0x0000..0x1000, &[0x2000..0x5000]);
409 assert(0x2000..0x5000, 0x0000..0x2000, &[0x2000..0x5000]);
410 assert(0x2000..0x5000, 0x0000..0x3000, &[0x3000..0x5000]);
411 assert(0x2000..0x5000, 0x0000..0x4000, &[0x4000..0x5000]);
412 assert(0x2000..0x5000, 0x0000..0x5000, &[]);
413 assert(0x2000..0x5000, 0x0000..0x6000, &[]);
414 assert(0x2000..0x5000, 0x0000..0x7000, &[]);
415 assert(0x2000..0x5000, 0x1000..0x7000, &[]);
416 assert(0x2000..0x5000, 0x2000..0x7000, &[]);
417 assert(0x2000..0x5000, 0x3000..0x7000, &[0x2000..0x3000]);
418 assert(0x2000..0x5000, 0x4000..0x7000, &[0x2000..0x4000]);
419 assert(0x2000..0x5000, 0x5000..0x7000, &[0x2000..0x5000]);
420 assert(0x2000..0x5000, 0x6000..0x7000, &[0x2000..0x5000]);
421
422 assert(0x2000..0x5000, 0x2000..0x3000, &[0x3000..0x5000]);
423 assert(0x2000..0x5000, 0x2000..0x4000, &[0x4000..0x5000]);
424 assert(0x2000..0x5000, 0x2000..0x5000, &[]);
425 assert(0x2000..0x5000, 0x3000..0x5000, &[0x2000..0x3000]);
426 assert(0x2000..0x5000, 0x4000..0x5000, &[0x2000..0x4000]);
427
428 assert(
429 0x2000..0x5000,
430 0x3000..0x4000,
431 &[0x2000..0x3000, 0x4000..0x5000],
432 );
433 }
434}