1#![no_std]
25#![forbid(unsafe_code)]
26
27pub trait Align<A = Self>: Copy + PartialEq {
29 fn align_down(self, align: A) -> Self;
35
36 fn align_up(self, align: A) -> Self;
42
43 #[allow(clippy::wrong_self_convention)]
45 #[inline]
46 fn is_aligned_to(self, align: A) -> bool {
47 self.align_down(align) == self
48 }
49}
50
51macro_rules! align_impl {
52 ($u:ty, $align_down:ident, $align_up:ident, $is_aligned_to:ident) => {
53 #[inline]
62 pub const fn $align_down(addr: $u, align: $u) -> $u {
63 assert!(align.is_power_of_two(), "`align` must be a power of two");
64 addr & !(align - 1)
65 }
66
67 #[inline]
76 pub const fn $align_up(addr: $u, align: $u) -> $u {
77 assert!(align.is_power_of_two(), "`align` must be a power of two");
78 let align_mask = align - 1;
79 if addr & align_mask == 0 {
80 addr } else {
82 if let Some(aligned) = (addr | align_mask).checked_add(1) {
84 aligned
85 } else {
86 panic!("attempt to add with overflow")
87 }
88 }
89 }
90
91 #[inline]
95 pub const fn $is_aligned_to(addr: $u, align: $u) -> bool {
96 $align_down(addr, align) == addr
97 }
98
99 impl Align for $u {
100 #[inline]
101 fn align_down(self, align: Self) -> Self {
102 $align_down(self, align)
103 }
104
105 #[inline]
106 fn align_up(self, align: Self) -> Self {
107 $align_up(self, align)
108 }
109 }
110 };
111}
112
113align_impl!(u8, u8_align_down, u8_align_up, u8_is_aligned_to);
114align_impl!(u16, u16_align_down, u16_align_up, u16_is_aligned_to);
115align_impl!(u32, u32_align_down, u32_align_up, u32_is_aligned_to);
116align_impl!(u64, u64_align_down, u64_align_up, u64_is_aligned_to);
117align_impl!(u128, u128_align_down, u128_align_up, u128_is_aligned_to);
118align_impl!(usize, usize_align_down, usize_align_up, usize_is_aligned_to);
119
120#[cfg(test)]
122mod tests {
123 use super::*;
124
125 macro_rules! test_align_up_impl {
126 ($u:ty, $align_up:ident, $test_align_up:ident) => {
127 #[test]
128 fn $test_align_up() {
129 assert_eq!($align_up(0, 1), 0);
131 assert_eq!($align_up(123, 1), 123);
132 assert_eq!($align_up(<$u>::MAX, 1), <$u>::MAX);
133 assert_eq!($align_up(0, 2), 0);
135 assert_eq!($align_up(123, 2), 124);
136 assert_eq!($align_up(<$u>::MAX - 1, 2), <$u>::MAX - 1);
137 assert_eq!($align_up(0, 128), 0);
139 assert_eq!($align_up(0, 1), 0);
140 assert_eq!($align_up(0, 2), 0);
141 assert_eq!($align_up(0, <$u>::MAX & 1 << (<$u>::BITS - 1)), 0);
142 }
143 };
144 }
145
146 test_align_up_impl!(u8, u8_align_up, test_u8_align_up);
147 test_align_up_impl!(u16, u16_align_up, test_u16_align_up);
148 test_align_up_impl!(u32, u32_align_up, test_u32_align_up);
149 test_align_up_impl!(u64, u64_align_up, test_u64_align_up);
150 test_align_up_impl!(u128, u128_align_up, test_u128_align_up);
151 test_align_up_impl!(usize, usize_align_up, test_usize_align_up);
152
153 macro_rules! test_align_up_overflow_impl {
154 ($u:ty, $test_align_up_overflow:ident, $two:expr) => {
155 #[test]
156 #[should_panic]
157 fn $test_align_up_overflow() {
158 <$u>::MAX.align_up($two);
159 }
160 };
161 }
162
163 test_align_up_overflow_impl!(u8, test_u8_align_up_overflow, 2);
164 test_align_up_overflow_impl!(u16, test_u16_align_up_overflow, 2);
165 test_align_up_overflow_impl!(u32, test_u32_align_up_overflow, 2);
166 test_align_up_overflow_impl!(u64, test_u64_align_up_overflow, 2);
167 test_align_up_overflow_impl!(u128, test_u128_align_up_overflow, 2);
168 test_align_up_overflow_impl!(usize, test_usize_align_up_overflow, 2);
169}