align_constr/
lib.rs

1#![doc = include_str!("../README.md")]
2#![no_std]
3
4/// [N-ZSTs](https://github.com/rust-lang/unsafe-code-guidelines/issues/172), i.e.
5/// [zero-sized datatypes](https://runrust.miraheze.org/wiki/Zero-sized_type) whose
6/// [alignment](https://www.geeksforgeeks.org/data-structure-alignment/) is `N`.
7///
8/// If you have to deal with larger alignments, please contact the author via the
9/// email provided in Cargo.toml or via an issue.
10pub mod n_zst {
11    /// 2-[ZST](https://runrust.miraheze.org/wiki/Zero-sized_type).
12    ///
13    /// Read more about n-ZSTs [here](https://github.com/rust-lang/unsafe-code-guidelines/issues/172)
14    #[repr(align(1))]
15    pub struct ZST1;
16
17    /// 2-[ZST](https://runrust.miraheze.org/wiki/Zero-sized_type).
18    ///
19    /// Read more about n-ZSTs [here](https://github.com/rust-lang/unsafe-code-guidelines/issues/172)
20    #[repr(align(2))]
21    pub struct ZST2;
22
23    /// 4-[ZST](https://runrust.miraheze.org/wiki/Zero-sized_type).
24    ///
25    /// Read more about n-ZSTs [here](https://github.com/rust-lang/unsafe-code-guidelines/issues/172)
26    #[repr(align(4))]
27    pub struct ZST4;
28
29    /// 8-[ZST](https://runrust.miraheze.org/wiki/Zero-sized_type).
30    ///
31    /// Read more about n-ZSTs [here](https://github.com/rust-lang/unsafe-code-guidelines/issues/172)
32    #[repr(align(8))]
33    pub struct ZST8;
34
35    /// 16-[ZST](https://runrust.miraheze.org/wiki/Zero-sized_type).
36    ///
37    /// Read more about n-ZSTs [here](https://github.com/rust-lang/unsafe-code-guidelines/issues/172)
38    #[repr(align(16))]
39    pub struct ZST16;
40
41    /// 32-[ZST](https://runrust.miraheze.org/wiki/Zero-sized_type).
42    ///
43    /// Read more about n-ZSTs [here](https://github.com/rust-lang/unsafe-code-guidelines/issues/172)
44    #[repr(align(32))]
45    pub struct ZST32;
46
47    /// 64-[ZST](https://runrust.miraheze.org/wiki/Zero-sized_type).
48    ///
49    /// Read more about n-ZSTs [here](https://github.com/rust-lang/unsafe-code-guidelines/issues/172)
50    #[repr(align(64))]
51    pub struct ZST64;
52
53    /// 128-[ZST](https://runrust.miraheze.org/wiki/Zero-sized_type).
54    ///
55    /// Read more about n-ZSTs [here](https://github.com/rust-lang/unsafe-code-guidelines/issues/172)
56    #[repr(align(128))]
57    pub struct ZST128;
58
59    /// 256-[ZST](https://runrust.miraheze.org/wiki/Zero-sized_type).
60    ///
61    /// Read more about n-ZSTs [here](https://github.com/rust-lang/unsafe-code-guidelines/issues/172)
62    #[repr(align(256))]
63    pub struct ZST256;
64
65    /// 512-[ZST](https://runrust.miraheze.org/wiki/Zero-sized_type).
66    ///
67    /// Read more about n-ZSTs [here](https://github.com/rust-lang/unsafe-code-guidelines/issues/172)
68    #[repr(align(512))]
69    pub struct ZST512;
70}
71
72/// Alignment-constrained datatype, i.e. a type whose
73/// [alignment](https://www.geeksforgeeks.org/data-structure-alignment/)
74/// is constrained not only by the inherent alignment requirements of the underlying type `T`, whose value
75/// is stored internally, but also by the alignment requirements of the "alignment constraint archetype"
76/// `AlignConstrArchetype`. Within this context, "alignment constraint archetype" `AlignConstrArchetype`
77/// is a type whose alignment constraint is imposed on the underlying type `T` to produce
78/// [`AlignConstr<T, AlignConstrArchetype>`][`AlignConstr`].
79///
80/// # Notes
81///
82/// * "alignment constraint archetype" is a
83/// [stipulative](https://www.ucfmapper.com/education/various-types-definitions/#:~:text=Stipulative%20definitions)
84/// [functional](https://www.ucfmapper.com/education/various-types-definitions/#:~:text=Functional%20definitions)
85/// definition.
86///
87/// * [`AlignConstr<T, AlignConstrArchetype>`][`AlignConstr`] for some underlying type `T` and
88/// "alignment constraint archetype" `AlignConstrArchetype` can also be seen as a
89/// [refinement type](https://en.wikipedia.org/wiki/Refinement_type)
90/// [reified](https://en.wikipedia.org/wiki/Reification_(computer_science)) in the form of a
91/// [parameterized](http://www.angelikalanger.com/GenericsFAQ/FAQSections/ParameterizedTypes.html#FAQ001)
92/// [newtype](https://rust-unofficial.github.io/patterns/patterns/behavioural/newtype.html).
93///
94/// Unlike in [`aligned`] crate, [`Deref`][`core::ops::Deref`] and [`DerefMut`][`core::ops::DerefMut`]
95/// are used not for accessing the underlying value but for dereferencing that value in case
96/// **if** it is possible. Therefore, the following code should fail to compile:
97///
98/// ```rust, compile_fail
99/// use align_constr::{AlignConstr, n_zst::ZST64};
100///
101/// fn deref_must_be_impossible_when_underlying_type_is_not_deref() {
102///     let overaligned_u8 = AlignConstr::<u8, ZST64>::new(3);
103///     // Since u8 doesn't implement Deref, neither does AlignConstr::<u8, ...>
104///     let smth = *overaligned_u8;
105/// }
106/// ```
107///
108/// and the one below must succeed:
109///
110/// ```rust
111/// use align_constr::{AlignConstr, n_zst::ZST128};
112///
113/// fn deref_is_performed_on_underlying_value() {
114///     let overaligned_u8_ref = AlignConstr::<&u8, ZST128>::new(&3);
115///     // Since &u8 implements Deref, so does AlignConstr::<&u8, ...>
116///     assert_eq!(*overaligned_u8_ref, 3);
117/// }
118///
119/// deref_is_performed_on_underlying_value();
120/// ```
121///
122/// The underlying value can be accessed via the `.value` field and
123/// it can be done in constant contexts even on stable Rust!
124///
125/// ```
126/// use align_constr::{AlignConstr, n_zst::ZST64};
127///
128/// const fn underlying_value_can_be_accessed_via_value_field() {
129///     let overaligned_u8 = AlignConstr::<u8, ZST64>::new(3);
130///     assert!(overaligned_u8.value == 3u8);
131/// }
132///
133/// underlying_value_can_be_accessed_via_value_field();
134/// ```
135///
136/// Here's a comprehensive list of traits that could be expected
137/// to be implemented for all reasonable
138/// [parameterized types](http://www.angelikalanger.com/GenericsFAQ/FAQSections/ParameterizedTypes.html#FAQ001)
139/// of [`AlignConstr`]
140/// constantly under [feature flags](https://doc.rust-lang.org/beta/unstable-book/)
141/// and non-constantly on stable Rust, yet it is not the case:
142///
143/// * [core::marker::Copy]
144/// > [`core::marker::Copy`] cannot be implemented for `T: `[`core::marker::Copy`] on
145/// > [`AlignConstr`]`<T, AlignConstrArchetype>` unconditionally due to the implementation thereof.
146/// >
147/// > At the time of writing, [`AlignConstr`] relies on a zero-length array
148/// > `[AlignConstrArchetype;0]`; but
149/// > [zero-length arrays are non-`Copy`](https://github.com/rust-lang/rust/issues/94313)
150/// > unless the type of the stored value (even 0 times) is `Copy`. That's why there is a temporary additional
151/// > condition `AlignConstrArchetype: Copy` for `[AlignConstrArchetype;0]` and, ultimately,
152/// > [`AlignConstr`]`<T, AlignConstrArchetype>: Copy`. Currently, there is no known alternative
153/// > for constraining the alignment other than `#[repr(align(N))]` where N is an integer literal.
154/// >
155/// > The author of [`aligned`] crate hasn't opened an issue when found this shortcoming and
156/// > didn't provide even a restricted version of `Copy` implementation.
157/// * [`core::ops::Index`]`<Idx>`
158/// > WIP (Work in Progress)
159/// >
160/// > The author of [`aligned`] crate implemented the trait only for
161/// > `Idx = `[`RangeTo`][core::ops::RangeTo]`<`[`usize`]`>`.
162///
163/// [`aligned`]: https://crates.io/crates/aligned
164// repr(C) enforces the order of fields
165#[repr(C)]
166pub struct AlignConstr<T, AlignConstrArchetype>
167where
168    T: ?Sized,
169{
170    _alignment_constraint: [AlignConstrArchetype; 0],
171    pub value: T,
172}
173
174// At the time of writing, `aligned` crate used the following constructor
175// for the analogous `Aligned` generic type:
176//
177// ```rust
178// #[allow(non_snake_case)]
179// pub const fn Aligned<A, T>(value: T) -> Aligned<A, T> {
180//     Aligned {
181//         _alignment: [],
182//         value,
183//     }
184// }
185// ```
186//
187// While shorter, it is believed to be currently non-idiomatic.
188//
189// Moreover, the alternative (the code below) can be rewritten as constant
190// implementation of New<T> trait
191impl<T, AlignConstrArchetype> AlignConstr<T, AlignConstrArchetype> {
192    /// Constructs a new alignment-constrained value
193    ///
194    /// # Examples
195    ///
196    /// Non-const context:
197    ///
198    /// ```
199    /// use align_constr::{AlignConstr, n_zst::ZST128};
200    ///
201    /// fn check_new() {
202    ///     let overaligned_u8 = AlignConstr::<u8, ZST128>::new(3);
203    ///     assert!(overaligned_u8.value == 3);
204    ///     // requires non-const context
205    ///     assert!(&overaligned_u8 as *const _ as usize % 128 == 0);
206    /// }
207    ///
208    /// check_new()
209    /// ```
210    ///
211    /// Const context:
212    /// ```
213    /// use align_constr::{AlignConstr, n_zst::ZST128};
214    ///
215    /// const fn const_check_new() {
216    ///     let overaligned_u8 = AlignConstr::<u8, ZST128>::new(3);
217    ///     assert!(overaligned_u8.value == 3);
218    /// }
219    /// ```
220    pub const fn new(value: T) -> AlignConstr<T, AlignConstrArchetype> {
221        AlignConstr {
222            _alignment_constraint: [],
223            value,
224        }
225    }
226}
227
228// At the time of writing, `aligned` crate unconditionally
229// non-constantly implemented Deref for
230// accessing the `value` field.
231impl<T, AlignConstrArchetype> core::ops::Deref for AlignConstr<T, AlignConstrArchetype>
232where
233    T: ?Sized + core::ops::Deref,
234{
235    type Target = <T as core::ops::Deref>::Target;
236
237    fn deref(&self) -> &Self::Target {
238        self.value.deref()
239    }
240}
241
242// At the time of writing, `aligned` crate unconditionally
243// non-constantly implemented DerefMut for
244// accessing the `value` field.
245impl<T, AlignConstrArchetype> core::ops::DerefMut for AlignConstr<T, AlignConstrArchetype>
246where
247    T: ?Sized + core::ops::DerefMut,
248{
249    fn deref_mut(&mut self) -> &mut <T as core::ops::Deref>::Target {
250        self.value.deref_mut()
251    }
252}
253
254impl<T, AlignConstrArchetype> core::ops::Index<core::ops::RangeTo<usize>>
255    for AlignConstr<[T], AlignConstrArchetype>
256where
257    [T]: core::ops::Index<core::ops::RangeTo<usize>, Output = [T]>,
258{
259    type Output = <[T] as core::ops::Index<core::ops::RangeTo<usize>>>::Output;
260
261    fn index(&self, range: core::ops::RangeTo<usize>) -> &Self::Output {
262        // The unsafe block has been this way in `aligned`
263        // TODO: figure out the intention and fix the code.
264        unsafe { &*(&self.value[range] as *const [T] as *const Self::Output) }
265    }
266}
267
268#[cfg(feature = "as_slice")]
269impl<T, AlignConstrArchetype> ::as_slice::AsSlice for AlignConstr<T, AlignConstrArchetype>
270where
271    T: ::as_slice::AsSlice,
272{
273    type Element = T::Element;
274
275    fn as_slice(&self) -> &[T::Element] {
276        self.value.as_slice()
277    }
278}
279
280#[cfg(feature = "as_slice")]
281impl<T, AlignConstrArchetype> ::as_slice::AsMutSlice for AlignConstr<T, AlignConstrArchetype>
282where
283    T: ::as_slice::AsMutSlice,
284{
285    fn as_mut_slice(&mut self) -> &mut [T::Element] {
286        self.value.as_mut_slice()
287    }
288}
289
290impl<T, AlignConstrArchetype> Clone for AlignConstr<T, AlignConstrArchetype>
291where
292    T: Clone,
293{
294    fn clone(&self) -> Self {
295        Self {
296            _alignment_constraint: [],
297            value: self.value.clone(),
298        }
299    }
300
301    fn clone_from(&mut self, source: &Self) {
302        self.value = source.value.clone();
303    }
304}
305
306impl<T, AlignConstrArchetype> Copy for AlignConstr<T, AlignConstrArchetype>
307where
308    T: Copy,
309    // At the time of writing, the bound below is necessary because
310    // zero-length arrays are non-Copy:
311    // https://github.com/rust-lang/rust/issues/94313
312    //
313    // Without lattice specialization, the condition for
314    // `[AlignConstrArchetype; 0]: Copy` is that `AlignConstrArchetype: Copy`
315    [AlignConstrArchetype; 0]: Copy,
316{
317}
318
319impl<T, AlignConstrArchetype> Default for AlignConstr<T, AlignConstrArchetype>
320where
321    T: Default,
322{
323    fn default() -> Self {
324        Self {
325            _alignment_constraint: [],
326            value: T::default(),
327        }
328    }
329}
330
331impl<T, AlignConstrArchetype> core::fmt::Debug for AlignConstr<T, AlignConstrArchetype>
332where
333    T: core::fmt::Debug,
334{
335    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
336        self.value.fmt(f)
337    }
338}
339
340impl<T, AlignConstrArchetype> core::fmt::Display for AlignConstr<T, AlignConstrArchetype>
341where
342    T: core::fmt::Display,
343{
344    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
345        self.value.fmt(f)
346    }
347}
348
349impl<T, AlignConstrArchetype> PartialEq for AlignConstr<T, AlignConstrArchetype>
350where
351    T: PartialEq,
352{
353    fn eq(&self, other: &Self) -> bool {
354        self.value == other.value
355    }
356}
357
358impl<T, AlignConstrArchetype> Eq for AlignConstr<T, AlignConstrArchetype>
359where
360    T: Eq,
361{
362    fn assert_receiver_is_total_eq(&self) {}
363}
364
365impl<T, AlignConstrArchetype> core::hash::Hash for AlignConstr<T, AlignConstrArchetype>
366where
367    T: core::hash::Hash,
368{
369    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
370        self.value.hash(state);
371    }
372
373    // The following is implemented due to
374    // error: const trait implementations may not use non-const default functions
375    fn hash_slice<H>(data: &[Self], state: &mut H)
376    where
377        Self: Sized,
378        H: core::hash::Hasher,
379    {
380        let mut i = 0;
381        while i < data.len() {
382            data[i].hash(state);
383            i += 1;
384        }
385    }
386}
387
388impl<T, AlignConstrArchetype> core::cmp::Ord for AlignConstr<T, AlignConstrArchetype>
389where
390    T: Ord,
391{
392    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
393        self.value.cmp(&other.value)
394    }
395}
396
397impl<T, AlignConstrArchetype> core::cmp::PartialOrd for AlignConstr<T, AlignConstrArchetype>
398where
399    T: PartialOrd,
400{
401    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
402        self.value.partial_cmp(&other.value)
403    }
404}
405
406#[cfg(test)]
407mod tests {
408    use crate::{
409        n_zst::{ZST1, ZST128, ZST16, ZST2, ZST256, ZST32, ZST4, ZST512, ZST64, ZST8},
410        AlignConstr,
411    };
412
413    #[test]
414    fn size_of_align_constr_t_geq_size_of_t() {
415        use core::mem::size_of;
416        assert!(size_of::<AlignConstr::<u8, u16>>() >= size_of::<u8>());
417    }
418
419    // This function tests the assumption about the relation
420    // between core::mem::align_of::<u8>() and core::mem::align_of::<ZST512>().
421    //
422    // Other tests might fail to check the intended behevior if this test fails.
423    #[test]
424    const fn align_of_u8_le_align_of_zst512() {
425        use core::mem::align_of;
426        assert!(align_of::<u8>() < align_of::<ZST512>());
427    }
428
429    #[test]
430    const fn check_alignments_of_n_zsts() {
431        use core::mem::align_of;
432
433        assert!(align_of::<ZST1>() == 1);
434        assert!(align_of::<ZST2>() == 2);
435        assert!(align_of::<ZST4>() == 4);
436        assert!(align_of::<ZST8>() == 8);
437        assert!(align_of::<ZST16>() == 16);
438        assert!(align_of::<ZST32>() == 32);
439        assert!(align_of::<ZST64>() == 64);
440        assert!(align_of::<ZST128>() == 128);
441        assert!(align_of::<ZST256>() == 256);
442        assert!(align_of::<ZST512>() == 512);
443    }
444
445    #[test]
446    const fn align_constr_allows_overaligning() {
447        use core::mem::align_of;
448
449        assert!(align_of::<AlignConstr::<u8, ZST512>>() > align_of::<u8>());
450    }
451
452    #[test]
453    const fn align_constr_doesnt_reduce_alignment() {
454        use core::mem::align_of;
455
456        assert!(align_of::<AlignConstr::<ZST512, u8>>() == align_of::<ZST512>());
457    }
458}