1#![no_std]
27#![forbid(unsafe_code)]
28
29pub trait Align<A = Self>: Copy + PartialEq {
31 #[must_use = "this returns the result of the operation, \
37 without modifying the original"]
38 #[track_caller]
39 fn align_down(self, align: A) -> Self;
40
41 #[must_use = "this returns the result of the operation, \
49 without modifying the original"]
50 #[track_caller]
51 fn checked_align_up(self, align: A) -> Option<Self>;
52
53 #[must_use = "this returns the result of the operation, \
59 without modifying the original"]
60 #[inline]
61 #[track_caller]
62 fn align_up(self, align: A) -> Self {
63 self.checked_align_up(align)
64 .expect("attempt to add with overflow")
65 }
66
67 #[allow(clippy::wrong_self_convention)]
69 #[must_use]
70 #[inline]
71 #[track_caller]
72 fn is_aligned_to(self, align: A) -> bool {
73 self.align_down(align) == self
74 }
75}
76
77macro_rules! align_impl {
78 ($u:ty, $align_down:ident, $checked_align_up:ident, $align_up:ident, $is_aligned_to:ident) => {
79 #[must_use = "this returns the result of the operation, \
88 without modifying the original"]
89 #[inline]
90 #[track_caller]
91 pub const fn $align_down(addr: $u, align: $u) -> $u {
92 assert!(align.is_power_of_two(), "`align` must be a power of two");
93 addr & !(align - 1)
94 }
95
96 #[must_use = "this returns the result of the operation, \
107 without modifying the original"]
108 #[inline]
109 #[track_caller]
110 pub const fn $checked_align_up(addr: $u, align: $u) -> Option<$u> {
111 assert!(align.is_power_of_two(), "`align` must be a power of two");
112 let align_mask = align - 1;
113 if addr & align_mask == 0 {
114 return Some(addr);
116 }
117
118 (addr | align_mask).checked_add(1)
119 }
120
121 #[must_use = "this returns the result of the operation, \
130 without modifying the original"]
131 #[inline]
132 #[track_caller]
133 pub const fn $align_up(addr: $u, align: $u) -> $u {
134 if let Some(aligned) = $checked_align_up(addr, align) {
136 aligned
137 } else {
138 panic!("attempt to add with overflow")
139 }
140 }
141
142 #[must_use]
146 #[inline]
147 #[track_caller]
148 pub const fn $is_aligned_to(addr: $u, align: $u) -> bool {
149 $align_down(addr, align) == addr
150 }
151
152 impl Align for $u {
153 #[inline]
154 fn align_down(self, align: Self) -> Self {
155 $align_down(self, align)
156 }
157
158 #[inline]
159 fn checked_align_up(self, align: Self) -> Option<Self> {
160 $checked_align_up(self, align)
161 }
162 }
163 };
164}
165
166align_impl!(
167 u8,
168 u8_align_down,
169 u8_checked_align_up,
170 u8_align_up,
171 u8_is_aligned_to
172);
173align_impl!(
174 u16,
175 u16_align_down,
176 u16_checked_align_up,
177 u16_align_up,
178 u16_is_aligned_to
179);
180align_impl!(
181 u32,
182 u32_align_down,
183 u32_checked_align_up,
184 u32_align_up,
185 u32_is_aligned_to
186);
187align_impl!(
188 u64,
189 u64_align_down,
190 u64_checked_align_up,
191 u64_align_up,
192 u64_is_aligned_to
193);
194align_impl!(
195 u128,
196 u128_align_down,
197 u128_checked_align_up,
198 u128_align_up,
199 u128_is_aligned_to
200);
201align_impl!(
202 usize,
203 usize_align_down,
204 usize_checked_align_up,
205 usize_align_up,
206 usize_is_aligned_to
207);
208
209#[cfg(test)]
211mod tests {
212 use super::*;
213
214 macro_rules! test_checked_align_up_impl {
215 ($u:ty, $checked_align_up:ident, $test_checked_align_up:ident) => {
216 #[test]
217 fn $test_checked_align_up() {
218 assert_eq!($checked_align_up(0, 1), Some(0));
220 assert_eq!($checked_align_up(123, 1), Some(123));
221 assert_eq!($checked_align_up(<$u>::MAX, 1), Some(<$u>::MAX));
222 assert_eq!($checked_align_up(0, 2), Some(0));
224 assert_eq!($checked_align_up(123, 2), Some(124));
225 assert_eq!($checked_align_up(<$u>::MAX - 1, 2), Some(<$u>::MAX - 1));
226 assert_eq!($checked_align_up(0, 128), Some(0));
228 assert_eq!($checked_align_up(0, 1), Some(0));
229 assert_eq!($checked_align_up(0, 2), Some(0));
230 assert_eq!(
231 $checked_align_up(0, <$u>::MAX & 1 << (<$u>::BITS - 1)),
232 Some(0)
233 );
234 assert_eq!($checked_align_up(<$u>::MAX, 2), None);
236 }
237 };
238 }
239
240 test_checked_align_up_impl!(u8, u8_checked_align_up, test_u8_checked_align_up);
241 test_checked_align_up_impl!(u16, u16_checked_align_up, test_u16_checked_align_up);
242 test_checked_align_up_impl!(u32, u32_checked_align_up, test_u32_checked_align_up);
243 test_checked_align_up_impl!(u64, u64_checked_align_up, test_u64_checked_align_up);
244 test_checked_align_up_impl!(u128, u128_checked_align_up, test_u128_checked_align_up);
245 test_checked_align_up_impl!(usize, usize_checked_align_up, test_usize_checked_align_up);
246}