encase/core/
alignment_value.rs1use super::SizeValue;
2use core::num::NonZeroU64;
3
4#[derive(Clone, Copy, Debug, PartialEq, Eq)]
6pub struct AlignmentValue(NonZeroU64);
7
8impl AlignmentValue {
9 pub const fn new(val: u64) -> Self {
10 if !val.is_power_of_two() {
11 panic!("Alignment must be a power of 2!");
12 }
13 Self(unsafe { NonZeroU64::new_unchecked(val) })
15 }
16
17 #[inline]
19 pub const fn from_next_power_of_two_size(size: SizeValue) -> Self {
20 match size.get().checked_next_power_of_two() {
21 None => panic!("Overflow occurred while getting the next power of 2!"),
22 Some(val) => {
23 Self(unsafe { NonZeroU64::new_unchecked(val) })
25 }
26 }
27 }
28
29 #[inline]
30 pub const fn get(&self) -> u64 {
31 self.0.get()
32 }
33
34 pub const fn max<const N: usize>(input: [AlignmentValue; N]) -> AlignmentValue {
36 let mut max = input[0];
37 let mut i = 1;
38
39 while i < N {
40 if input[i].get() > max.get() {
41 max = input[i];
42 }
43
44 i += 1;
45 }
46
47 max
48 }
49
50 #[inline]
52 pub const fn is_aligned(&self, n: u64) -> bool {
53 n % self.get() == 0
54 }
55
56 #[inline]
58 pub const fn padding_needed_for(&self, n: u64) -> u64 {
59 let r = n % self.get();
60 if r > 0 {
61 self.get() - r
62 } else {
63 0
64 }
65 }
66
67 #[inline]
69 pub const fn round_up(&self, n: u64) -> u64 {
70 n + self.padding_needed_for(n)
71 }
72
73 #[inline]
75 pub const fn round_up_size(&self, n: SizeValue) -> SizeValue {
76 SizeValue::new(self.round_up(n.get()))
77 }
78}
79
80#[cfg(test)]
81mod test {
82 use super::AlignmentValue;
83 use alloc::format;
84
85 #[test]
86 fn new() {
87 assert_eq!(4, AlignmentValue::new(4).get());
88 }
89
90 #[test]
91 #[should_panic]
92 fn new_panic() {
93 AlignmentValue::new(3);
94 }
95
96 #[test]
97 fn from_next_power_of_two_size() {
98 assert_eq!(
99 AlignmentValue::new(8),
100 AlignmentValue::from_next_power_of_two_size(super::SizeValue::new(7))
101 );
102 }
103
104 #[test]
105 #[should_panic]
106 fn from_next_power_of_two_size_panic() {
107 AlignmentValue::from_next_power_of_two_size(super::SizeValue::new(u64::MAX));
108 }
109
110 #[test]
111 fn max() {
112 assert_eq!(
113 AlignmentValue::new(32),
114 AlignmentValue::max([
115 AlignmentValue::new(2),
116 AlignmentValue::new(8),
117 AlignmentValue::new(32)
118 ])
119 );
120 }
121
122 #[test]
123 fn is_aligned() {
124 assert!(AlignmentValue::new(8).is_aligned(32));
125 assert!(!AlignmentValue::new(8).is_aligned(9));
126 }
127
128 #[test]
129 fn padding_needed_for() {
130 assert_eq!(1, AlignmentValue::new(8).padding_needed_for(7));
131 assert_eq!(16 - 9, AlignmentValue::new(8).padding_needed_for(9));
132 }
133
134 #[test]
135 fn round_up() {
136 assert_eq!(24, AlignmentValue::new(8).round_up(20));
137 assert_eq!(
138 super::SizeValue::new(16),
139 AlignmentValue::new(16).round_up_size(super::SizeValue::new(7))
140 );
141 }
142
143 #[test]
144 fn derived_traits() {
145 let alignment = AlignmentValue::new(8);
146 #[allow(clippy::clone_on_copy)]
147 let alignment_clone = alignment.clone();
148
149 assert!(alignment == alignment_clone);
150
151 assert_eq!(format!("{alignment:?}"), "AlignmentValue(8)");
152 }
153}