use crate::errors::{MmapIoError, Result};
use std::sync::OnceLock;
static PAGE_SIZE: OnceLock<usize> = OnceLock::new();
#[must_use]
pub fn page_size() -> usize {
*PAGE_SIZE.get_or_init(query_page_size)
}
fn query_page_size() -> usize {
cfg_if::cfg_if! {
if #[cfg(target_os = "windows")] {
windows_page_size()
} else {
unix_page_size()
}
}
}
#[cfg(target_os = "windows")]
fn windows_page_size() -> usize {
use std::mem::MaybeUninit;
#[allow(non_snake_case)]
#[repr(C)]
struct SYSTEM_INFO {
wProcessorArchitecture: u16,
wReserved: u16,
dwPageSize: u32,
lpMinimumApplicationAddress: *mut core::ffi::c_void,
lpMaximumApplicationAddress: *mut core::ffi::c_void,
dwActiveProcessorMask: usize,
dwNumberOfProcessors: u32,
dwProcessorType: u32,
dwAllocationGranularity: u32,
wProcessorLevel: u16,
wProcessorRevision: u16,
}
extern "system" {
fn GetSystemInfo(lpSystemInfo: *mut SYSTEM_INFO);
}
let mut sysinfo = MaybeUninit::<SYSTEM_INFO>::uninit();
unsafe {
GetSystemInfo(sysinfo.as_mut_ptr());
let s = sysinfo.assume_init();
s.dwPageSize as usize
}
}
#[cfg(not(target_os = "windows"))]
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
fn unix_page_size() -> usize {
unsafe {
let page_size = libc::sysconf(libc::_SC_PAGESIZE);
page_size.max(0) as usize
}
}
#[inline]
#[must_use]
pub fn align_up(value: u64, alignment: u64) -> u64 {
if alignment == 0 {
return value;
}
if alignment.is_power_of_two() {
let mask = alignment - 1;
(value + mask) & !mask
} else {
value.div_ceil(alignment) * alignment
}
}
#[inline]
pub fn ensure_in_bounds(offset: u64, len: u64, total: u64) -> Result<()> {
let end = offset.saturating_add(len);
if end > total || offset > total {
return Err(MmapIoError::OutOfBounds { offset, len, total });
}
Ok(())
}
#[inline]
#[allow(clippy::cast_possible_truncation)]
pub fn slice_range(offset: u64, len: u64, total: u64) -> Result<(usize, usize)> {
ensure_in_bounds(offset, len, total)?;
let start = offset as usize;
let end = (offset + len) as usize;
Ok((start, end))
}