dungeon_cell/align.rs
1//! Alignment forcing wrappers.
2
3mod unaligned;
4
5use core::ops::{Deref, DerefMut};
6
7use crate::compile_time::const_transmute;
8use crate::marker_traits::IsAlignment;
9
10pub use unaligned::Unaligned;
11
12/// Force minimum alignment of a type.
13///
14/// # Invariants
15///
16/// The wrapped [`Self::value`] is guaranteed, for specifically unsafe code, to have
17/// a minimum alignment of [`Alignment::VALUE`][crate::marker_traits::IsAlignment::VALUE]
18/// bytes. The wrapped `value` is also guaranteed
19/// to have a zero offset from the start of the alignment block. This makes
20/// it sound to construct a reference the wrapped `value` for a different type
21/// with an alignment of maximum [`Alignment::VALUE`][crate::marker_traits::IsAlignment::VALUE]
22/// bytes, given the other unsafe rules
23/// are followed.
24///
25/// Additionally the layout of this struct is `#[repr(C)]` with a single field
26/// `value` of type `T` and a private zero sized type with an alignment of
27/// [`Alignment::VALUE`][crate::marker_traits::IsAlignment::VALUE] bytes.
28///
29/// # Examples
30///
31/// ```
32/// use std::mem::*;
33/// use dungeon_cell::align::Aligned;
34/// use dungeon_cell::layout::Alignment;
35///
36/// // 1 byte aligned buffer
37/// let x: [u8; 4] = 1234567890u32.to_ne_bytes();
38/// assert_eq!(size_of_val(&x), 4);
39/// assert_eq!(align_of_val(&x), 1);
40///
41/// // 4 byte aligned buffer
42/// let y = Aligned::<_, Alignment<4>>::new(x);
43/// assert_eq!(size_of_val(&y), 4);
44/// assert_eq!(align_of_val(&y), 4);
45///
46/// // this cast back to a u32 is sound because Aligned
47/// // makes the value field aligned to 4 bytes
48/// let z = &y.value as *const [u8; 4] as *const u32;
49/// let z = unsafe { &*z };
50/// assert_eq!(z, &1234567890);
51/// ```
52///
53#[repr(C)]
54pub struct Aligned<T, Alignment: IsAlignment> {
55 /// Stored value.
56 ///
57 /// This field is guaranteed to be aligned to
58 /// [`Alignment::VALUE`][crate::marker_traits::IsAlignment::VALUE] bytes.
59 pub value: T,
60
61 /// ZST to force the alignment of this struct.
62 ///
63 /// "The alignment of the struct is the alignment of the most-aligned field in it."
64 /// <https://doc.rust-lang.org/reference/type-layout.html#reprc-structs>
65 _alignment_marker: <Alignment as IsAlignment>::Marker,
66}
67
68impl<T: Copy, Alignment: IsAlignment> Copy for Aligned<T, Alignment> {}
69
70impl<T: Clone, Alignment: IsAlignment> Clone for Aligned<T, Alignment> {
71 fn clone(&self) -> Self {
72 Self {
73 value: self.value.clone(),
74 _alignment_marker: <Alignment as IsAlignment>::MARKER_INSTANCE,
75 }
76 }
77}
78
79impl<T, Alignment: IsAlignment> Aligned<T, Alignment> {
80 /// Construct a new aligned value.
81 ///
82 /// # Examples
83 /// ```
84 /// use dungeon_cell::align::Aligned;
85 /// use dungeon_cell::layout::Alignment;
86 ///
87 /// let a = Aligned::<_, Alignment<16>>::new(4);
88 ///
89 /// assert_eq!(a.value, 4);
90 /// ```
91 pub const fn new(value: T) -> Self {
92 Self {
93 value,
94 _alignment_marker: <Alignment as IsAlignment>::MARKER_INSTANCE,
95 }
96 }
97
98 /// Convert to the inner `T`.
99 ///
100 /// The returned value does not keep it's alignment and has the alignment of type `T`.
101 ///
102 /// # Examples
103 /// ```
104 /// use dungeon_cell::align::Aligned;
105 /// use dungeon_cell::layout::Alignment;
106 ///
107 /// let aligned = Aligned::<_, Alignment<16>>::new(4);
108 /// let num = Aligned::into_inner(aligned);
109 ///
110 /// assert_eq!(num, 4);
111 /// ```
112 pub const fn into_inner(this: Self) -> T {
113 // SAFETY: This stuct has `repr(C)` with the type `T` first and a ZST after it.
114 unsafe { const_transmute::<Self, T>(this) }
115 }
116}
117
118impl<T, Alignment: IsAlignment> Deref for Aligned<T, Alignment> {
119 type Target = T;
120
121 fn deref(&self) -> &Self::Target {
122 &self.value
123 }
124}
125
126impl<T, Alignment: IsAlignment> DerefMut for Aligned<T, Alignment> {
127 fn deref_mut(&mut self) -> &mut Self::Target {
128 &mut self.value
129 }
130}
131
132#[cfg(test)]
133mod test {
134 use crate::layout::Alignment;
135 use core::mem::{align_of, align_of_val, size_of, size_of_val};
136
137 use super::*;
138
139 #[test]
140 fn aligned_is_just_a_wrapper_around_a_value() {
141 let x = Aligned::<_, Alignment<1>>::new(123i32);
142
143 assert_eq!(size_of_val(&x), size_of::<i32>());
144 assert_eq!(align_of_val(&x), align_of::<i32>());
145
146 assert_eq!(Aligned::into_inner(x), 123);
147
148 let x = Aligned::<_, Alignment<1>>::new(String::from("abc"));
149
150 assert_eq!(size_of_val(&x), size_of::<String>());
151 assert_eq!(align_of_val(&x), align_of::<String>());
152
153 assert_eq!(Aligned::into_inner(x), "abc");
154 }
155
156 #[test]
157 fn aligned_acts_as_a_smart_pointer() {
158 let mut x = Aligned::<_, Alignment<8>>::new(123i32);
159 assert_eq!(*x, 123);
160
161 *x += 1;
162 assert_eq!(*x, 124);
163 }
164
165 #[test]
166 fn aligned_forces_minimum_alignment() {
167 // u32 already has an alignment of 4.
168 assert_eq!(align_of::<Aligned::<u32, Alignment<1>>>(), 4);
169 assert_eq!(align_of::<Aligned::<u32, Alignment<2>>>(), 4);
170 assert_eq!(align_of::<Aligned::<u32, Alignment<4>>>(), 4);
171
172 assert_eq!(align_of::<Aligned::<u32, Alignment<8>>>(), 8);
173 assert_eq!(align_of::<Aligned::<u32, Alignment<64>>>(), 64);
174 assert_eq!(
175 align_of::<Aligned::<u32, Alignment<536_870_912>>>(),
176 536_870_912
177 );
178
179 // no nudge
180 assert_eq!(align_of::<Aligned::<u8, Alignment<1>>>(), 1);
181
182 // little nudge
183 assert_eq!(align_of::<Aligned::<u8, Alignment<2>>>(), 2);
184
185 // BIG nugde
186 assert_eq!(
187 align_of::<Aligned::<u8, Alignment<536_870_912>>>(),
188 536_870_912
189 );
190 }
191}