region/
page.rs

1//! Page related functions.
2
3use crate::os;
4use std::sync::Once;
5
6/// Returns the operating system's page size.
7///
8/// This function uses an internally cached page size, and can be called
9/// repeatedly without incurring a significant performance penalty.
10///
11/// # Examples
12///
13/// ```
14/// # use region::page;
15/// let size = page::size(); // Most likely 4096
16/// ```
17#[inline]
18pub fn size() -> usize {
19  static INIT: Once = Once::new();
20  static mut PAGE_SIZE: usize = 0;
21
22  unsafe {
23    INIT.call_once(|| PAGE_SIZE = os::page_size());
24    PAGE_SIZE
25  }
26}
27
28/// Rounds an address down to its closest page boundary.
29///
30/// # Examples
31///
32/// ```
33/// # use region::page;
34/// let unaligned_pointer = (page::size() + 1) as *const ();
35///
36/// assert_eq!(page::floor(unaligned_pointer), page::size() as *const _);
37/// ```
38#[inline]
39pub fn floor<T>(address: *const T) -> *const T {
40  (address as usize & !(size() - 1)) as *const T
41}
42
43/// Rounds an address up to its closest page boundary.
44///
45/// # Examples
46///
47/// ```
48/// # use region::page;
49/// let unaligned_pointer = (page::size() - 1) as *const ();
50///
51/// assert_eq!(page::ceil(unaligned_pointer), page::size() as *const _);
52/// ```
53#[inline]
54pub fn ceil<T>(address: *const T) -> *const T {
55  match (address as usize).checked_add(size()) {
56    Some(offset) => ((offset - 1) & !(size() - 1)) as *const T,
57    None => floor(address),
58  }
59}
60
61#[cfg(test)]
62mod tests {
63  use super::*;
64
65  #[test]
66  fn page_size_is_reasonable() {
67    let pz = size();
68
69    assert!(pz > 0);
70    assert_eq!(pz % 2, 0);
71    assert_eq!(pz, size());
72  }
73
74  #[test]
75  fn page_rounding_works() {
76    let pz = size();
77    let point = 1 as *const ();
78
79    assert_eq!(floor(point) as usize, 0);
80    assert_eq!(floor(pz as *const ()) as usize, pz);
81    assert_eq!(floor(usize::max_value() as *const ()) as usize % pz, 0);
82
83    assert_eq!(ceil(point) as usize, pz);
84    assert_eq!(ceil(pz as *const ()) as usize, pz);
85    assert_eq!(ceil(usize::max_value() as *const ()) as usize % pz, 0);
86  }
87}