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}