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
84 #[test]
85 fn new() {
86 assert_eq!(4, AlignmentValue::new(4).get());
87 }
88
89 #[test]
90 #[should_panic]
91 fn new_panic() {
92 AlignmentValue::new(3);
93 }
94
95 #[test]
96 fn from_next_power_of_two_size() {
97 assert_eq!(
98 AlignmentValue::new(8),
99 AlignmentValue::from_next_power_of_two_size(super::SizeValue::new(7))
100 );
101 }
102
103 #[test]
104 #[should_panic]
105 fn from_next_power_of_two_size_panic() {
106 AlignmentValue::from_next_power_of_two_size(super::SizeValue::new(u64::MAX));
107 }
108
109 #[test]
110 fn max() {
111 assert_eq!(
112 AlignmentValue::new(32),
113 AlignmentValue::max([
114 AlignmentValue::new(2),
115 AlignmentValue::new(8),
116 AlignmentValue::new(32)
117 ])
118 );
119 }
120
121 #[test]
122 fn is_aligned() {
123 assert!(AlignmentValue::new(8).is_aligned(32));
124 assert!(!AlignmentValue::new(8).is_aligned(9));
125 }
126
127 #[test]
128 fn padding_needed_for() {
129 assert_eq!(1, AlignmentValue::new(8).padding_needed_for(7));
130 assert_eq!(16 - 9, AlignmentValue::new(8).padding_needed_for(9));
131 }
132
133 #[test]
134 fn round_up() {
135 assert_eq!(24, AlignmentValue::new(8).round_up(20));
136 assert_eq!(
137 super::SizeValue::new(16),
138 AlignmentValue::new(16).round_up_size(super::SizeValue::new(7))
139 );
140 }
141
142 #[test]
143 fn derived_traits() {
144 let alignment = AlignmentValue::new(8);
145 #[allow(clippy::clone_on_copy)]
146 let alignment_clone = alignment.clone();
147
148 assert!(alignment == alignment_clone);
149
150 assert_eq!(format!("{alignment:?}"), "AlignmentValue(8)");
151 }
152}