use crate::Bytes;
use core::fmt;
use core::marker::PhantomData;
use core::ops::Add;
use core::ops::AddAssign;
use core::ops::Div;
use core::ops::DivAssign;
use core::ops::Mul;
use core::ops::MulAssign;
use core::ops::Sub;
use core::ops::SubAssign;
use x86_64::structures::paging::PageSize;
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct NumOfPages<T: PageSize> {
num_of_pages: usize,
_marker: PhantomData<fn() -> T>,
}
impl<T: PageSize> NumOfPages<T> {
#[must_use]
pub fn new(num_of_pages: usize) -> Self {
Self {
num_of_pages,
_marker: PhantomData,
}
}
#[must_use]
pub fn zero() -> Self {
Self::new(0)
}
#[must_use]
pub fn as_usize(self) -> usize {
self.num_of_pages
}
#[must_use]
pub fn as_bytes(self) -> Bytes {
#[allow(clippy::cast_possible_truncation)]
Bytes::new(self.num_of_pages * T::SIZE as usize)
}
}
impl<T: PageSize> Add for NumOfPages<T> {
type Output = NumOfPages<T>;
fn add(self, rhs: NumOfPages<T>) -> Self {
Self::new(self.num_of_pages + rhs.num_of_pages)
}
}
impl<T: PageSize> Add<usize> for NumOfPages<T> {
type Output = NumOfPages<T>;
fn add(self, rhs: usize) -> Self::Output {
Self::new(self.num_of_pages + rhs)
}
}
impl<T: PageSize> AddAssign for NumOfPages<T> {
fn add_assign(&mut self, rhs: NumOfPages<T>) {
self.num_of_pages += rhs.num_of_pages;
}
}
impl<T: PageSize> AddAssign<usize> for NumOfPages<T> {
fn add_assign(&mut self, rhs: usize) {
self.num_of_pages += rhs;
}
}
impl<T: PageSize> Sub for NumOfPages<T> {
type Output = NumOfPages<T>;
fn sub(self, rhs: NumOfPages<T>) -> Self {
Self::new(self.num_of_pages - rhs.num_of_pages)
}
}
impl<T: PageSize> Sub<usize> for NumOfPages<T> {
type Output = NumOfPages<T>;
fn sub(self, rhs: usize) -> Self::Output {
Self::new(self.num_of_pages - rhs)
}
}
impl<T: PageSize> SubAssign for NumOfPages<T> {
fn sub_assign(&mut self, rhs: NumOfPages<T>) {
self.num_of_pages -= rhs.num_of_pages;
}
}
impl<T: PageSize> SubAssign<usize> for NumOfPages<T> {
fn sub_assign(&mut self, rhs: usize) {
*self -= Self::new(rhs);
}
}
impl<T: PageSize> Mul<usize> for NumOfPages<T> {
type Output = NumOfPages<T>;
fn mul(self, rhs: usize) -> Self::Output {
Self {
num_of_pages: self.num_of_pages * rhs,
..self
}
}
}
impl<T: PageSize> MulAssign<usize> for NumOfPages<T> {
fn mul_assign(&mut self, rhs: usize) {
*self = *self * rhs;
}
}
impl<T: PageSize> Div<usize> for NumOfPages<T> {
type Output = NumOfPages<T>;
fn div(self, rhs: usize) -> Self::Output {
Self {
num_of_pages: self.num_of_pages / rhs,
..self
}
}
}
impl<T: PageSize> DivAssign<usize> for NumOfPages<T> {
fn div_assign(&mut self, rhs: usize) {
*self = *self / rhs;
}
}
impl<T: PageSize> From<usize> for NumOfPages<T> {
fn from(n: usize) -> Self {
Self::new(n)
}
}
impl<T: PageSize> fmt::Debug for NumOfPages<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"NumOfPages::<{}>({})",
T::SIZE_AS_DEBUG_STR,
self.num_of_pages
)
}
}
impl<T: PageSize> fmt::Display for NumOfPages<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let unit = if self.num_of_pages == 1 {
"page"
} else {
"pages"
};
write!(
f,
"{} {} ({})",
self.num_of_pages,
unit,
T::SIZE_AS_DEBUG_STR
)
}
}
#[cfg(test)]
mod tests {
use super::NumOfPages;
use x86_64::structures::paging::Size1GiB;
use x86_64::structures::paging::Size2MiB;
use x86_64::structures::paging::Size4KiB;
#[test]
fn get_value_from_num_of_pages() {
let pages = NumOfPages::<Size4KiB>::new(334);
assert_eq!(pages.as_usize(), 334);
}
#[test]
fn pages_to_bytes_4k() {
let num_of_pages = NumOfPages::<Size4KiB>::new(1);
assert_eq!(num_of_pages.as_bytes().as_usize(), 0x1000);
}
#[test]
fn pages_to_bytes_2m() {
let num_of_pages = NumOfPages::<Size2MiB>::new(1);
assert_eq!(num_of_pages.as_bytes().as_usize(), 0x200000);
}
#[test]
fn pages_to_bytes_1g() {
let num_of_pages = NumOfPages::<Size1GiB>::new(1);
assert_eq!(num_of_pages.as_bytes().as_usize(), 0x40000000);
}
#[test]
fn addition_pages_to_pages() {
let p1 = NumOfPages::<Size4KiB>::new(3);
let p2 = NumOfPages::<Size4KiB>::new(1);
let sum = p1 + p2;
assert_eq!(sum.as_usize(), 4);
}
#[test]
fn add_usize_to_num_of_pages() {
let n = NumOfPages::<Size4KiB>::new(3);
assert_eq!(n + 7, NumOfPages::new(10));
}
#[test]
fn subtraction_pages_from_pages() {
let p1 = NumOfPages::<Size4KiB>::new(3);
let p2 = NumOfPages::<Size4KiB>::new(1);
let diff = p1 - p2;
assert_eq!(diff.as_usize(), 2);
}
#[test]
fn subtract_usize_from_num_of_pages() {
let n = NumOfPages::<Size4KiB>::new(5);
assert_eq!(n - 3, NumOfPages::new(2));
}
#[test]
fn add_assign_pages_to_pages() {
let mut p1 = NumOfPages::<Size4KiB>::new(3);
p1 += NumOfPages::<Size4KiB>::new(1);
assert_eq!(p1.as_usize(), 4);
}
#[test]
fn add_assign_usize_to_pages() {
let mut p1 = NumOfPages::<Size4KiB>::new(3);
p1 += 1;
assert_eq!(p1.as_usize(), 4);
}
#[test]
fn sub_assign_pages_to_pages() {
let mut p1 = NumOfPages::<Size4KiB>::new(3);
p1 -= NumOfPages::<Size4KiB>::new(1);
assert_eq!(p1.as_usize(), 2);
}
#[test]
fn sub_assign_usize_to_num_of_pages() {
let mut p1 = NumOfPages::<Size4KiB>::new(10);
p1 -= 3;
assert_eq!(p1, NumOfPages::new(7));
}
#[test]
fn mul_pages_by_usize() {
let p = NumOfPages::<Size4KiB>::new(3);
let mul = p * 4;
assert_eq!(mul.as_usize(), 12);
}
#[test]
fn mul_assign_pages_by_usize() {
let mut p = NumOfPages::<Size4KiB>::new(3);
p *= 4;
assert_eq!(p.as_usize(), 12);
}
#[test]
fn div_num_of_pages_by_usize() {
let p1 = NumOfPages::<Size4KiB>::new(3);
let div = p1 / 2;
assert_eq!(div.as_usize(), 1);
}
#[test]
fn divassign_num_of_pages_by_usize() {
let mut p = NumOfPages::<Size4KiB>::new(3);
p /= 2;
assert_eq!(p.as_usize(), 1);
}
#[test]
fn num_of_pages_zero() {
let n = NumOfPages::<Size4KiB>::zero();
assert_eq!(n.as_usize(), 0);
}
#[test]
fn from() {
let n = NumOfPages::<Size4KiB>::from(3);
assert_eq!(n, NumOfPages::new(3));
}
#[test]
fn debug_4k() {
let n = NumOfPages::<Size4KiB>::new(3);
let f = format!("{:?}", n);
assert_eq!(format!("NumOfPages::<4KiB>(3)"), f);
}
#[test]
fn debug_2m() {
let n = NumOfPages::<Size2MiB>::new(3);
let f = format!("{:?}", n);
assert_eq!(format!("NumOfPages::<2MiB>(3)"), f);
}
#[test]
fn debug_1g() {
let n = NumOfPages::<Size1GiB>::new(3);
let f = format!("{:?}", n);
assert_eq!(format!("NumOfPages::<1GiB>(3)"), f);
}
#[test]
fn display_0() {
let n = NumOfPages::<Size4KiB>::zero();
let f = format!("{}", n);
assert_eq!(format!("0 pages (4KiB)"), f);
}
#[test]
fn display_1() {
let n = NumOfPages::<Size4KiB>::new(1);
let f = format!("{}", n);
assert_eq!(format!("1 page (4KiB)"), f);
}
#[test]
fn display_2() {
let n = NumOfPages::<Size4KiB>::new(2);
let f = format!("{}", n);
assert_eq!(format!("2 pages (4KiB)"), f);
}
#[test]
fn display_2m() {
let n = NumOfPages::<Size2MiB>::zero();
let f = format!("{}", n);
assert_eq!(format!("0 pages (2MiB)"), f);
}
#[test]
fn display_1g() {
let n = NumOfPages::<Size1GiB>::zero();
let f = format!("{}", n);
assert_eq!(format!("0 pages (1GiB)"), f);
}
}