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}