1use crate::lib::std::convert::TryFrom;
2use crate::lib::std::fmt;
3use crate::lib::std::ops::{Add, Sub};
4use std::convert::TryInto;
5use thiserror::Error;
6
7pub const WASM_PAGE_SIZE: usize = 0x10000;
12
13pub const WASM_MAX_PAGES: u32 = 0x10000;
15
16pub const WASM_MIN_PAGES: u32 = 0x100;
18
19#[derive(
21 Copy,
22 Clone,
23 PartialEq,
24 Eq,
25 PartialOrd,
26 Ord,
27 Hash,
28 rkyv::Serialize,
29 rkyv::Deserialize,
30 rkyv::Archive,
31)]
32#[repr(transparent)]
33pub struct Pages(pub u32);
34
35impl Pages {
36 #[inline(always)]
40 pub const fn max_value() -> Self {
41 Self(WASM_MAX_PAGES)
42 }
43
44 pub fn checked_add(self, rhs: Self) -> Option<Self> {
47 let added = (self.0 as usize) + (rhs.0 as usize);
48 if added <= (WASM_MAX_PAGES as usize) {
49 Some(Self(added as u32))
50 } else {
51 None
52 }
53 }
54
55 pub fn bytes(self) -> Bytes {
57 self.into()
58 }
59}
60
61impl fmt::Debug for Pages {
62 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
63 write!(f, "{} pages", self.0)
64 }
65}
66
67impl From<u32> for Pages {
68 fn from(other: u32) -> Self {
69 Self(other)
70 }
71}
72
73#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
75pub struct Bytes(pub usize);
76
77impl fmt::Debug for Bytes {
78 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
79 write!(f, "{} bytes", self.0)
80 }
81}
82
83impl From<Pages> for Bytes {
84 fn from(pages: Pages) -> Self {
85 Self((pages.0 as usize) * WASM_PAGE_SIZE)
86 }
87}
88
89impl From<usize> for Bytes {
90 fn from(other: usize) -> Self {
91 Self(other)
92 }
93}
94
95impl From<u32> for Bytes {
96 fn from(other: u32) -> Self {
97 Self(other.try_into().unwrap())
98 }
99}
100
101impl<T> Sub<T> for Pages
102where
103 T: Into<Self>,
104{
105 type Output = Self;
106 fn sub(self, rhs: T) -> Self {
107 Self(self.0 - rhs.into().0)
108 }
109}
110
111impl<T> Add<T> for Pages
112where
113 T: Into<Self>,
114{
115 type Output = Self;
116 fn add(self, rhs: T) -> Self {
117 Self(self.0 + rhs.into().0)
118 }
119}
120
121#[derive(Debug, Clone, Copy, PartialEq, Error)]
123#[error("Number of pages exceeds uint32 range")]
124pub struct PageCountOutOfRange;
125
126impl TryFrom<Bytes> for Pages {
127 type Error = PageCountOutOfRange;
128
129 fn try_from(bytes: Bytes) -> Result<Self, Self::Error> {
130 let pages: u32 = (bytes.0 / WASM_PAGE_SIZE).try_into().or(Err(PageCountOutOfRange))?;
131 Ok(Self(pages))
132 }
133}
134
135impl<T> Sub<T> for Bytes
136where
137 T: Into<Self>,
138{
139 type Output = Self;
140 fn sub(self, rhs: T) -> Self {
141 Self(self.0 - rhs.into().0)
142 }
143}
144
145impl<T> Add<T> for Bytes
146where
147 T: Into<Self>,
148{
149 type Output = Self;
150 fn add(self, rhs: T) -> Self {
151 Self(self.0 + rhs.into().0)
152 }
153}
154
155#[cfg(test)]
156mod tests {
157 use super::*;
158
159 #[test]
160 fn convert_bytes_to_pages() {
161 let pages = Pages::try_from(Bytes(0)).unwrap();
163 assert_eq!(pages, Pages(0));
164 let pages = Pages::try_from(Bytes(1)).unwrap();
165 assert_eq!(pages, Pages(0));
166 let pages = Pages::try_from(Bytes(WASM_PAGE_SIZE - 1)).unwrap();
167 assert_eq!(pages, Pages(0));
168 let pages = Pages::try_from(Bytes(WASM_PAGE_SIZE)).unwrap();
169 assert_eq!(pages, Pages(1));
170 let pages = Pages::try_from(Bytes(WASM_PAGE_SIZE + 1)).unwrap();
171 assert_eq!(pages, Pages(1));
172 let pages = Pages::try_from(Bytes(28 * WASM_PAGE_SIZE + 42)).unwrap();
173 assert_eq!(pages, Pages(28));
174 let pages = Pages::try_from(Bytes((u32::MAX as usize) * WASM_PAGE_SIZE)).unwrap();
175 assert_eq!(pages, Pages(u32::MAX));
176 let pages = Pages::try_from(Bytes((u32::MAX as usize) * WASM_PAGE_SIZE + 1)).unwrap();
177 assert_eq!(pages, Pages(u32::MAX));
178
179 let result = Pages::try_from(Bytes((u32::MAX as usize + 1) * WASM_PAGE_SIZE));
181 assert_eq!(result.unwrap_err(), PageCountOutOfRange);
182 let result = Pages::try_from(Bytes(usize::MAX));
183 assert_eq!(result.unwrap_err(), PageCountOutOfRange);
184 }
185}