dync/
elem.rs

1//!
2//! This type defines types and traits useful for representing elements in untyped containers.
3//!
4
5use std::{
6    any::{Any, TypeId},
7    mem::{align_of, size_of},
8};
9
10macro_rules! generate_aligned_types {
11    ($($t:ident($n:expr),)*) => {
12	$(
13	    #[derive(Copy, Clone, Debug)]
14	    #[repr(C, align($n))]
15	    pub(crate) struct $t([u8; $n]);
16
17        impl Default for $t {
18            fn default() -> Self {
19                $t([0_u8; $n])
20            }
21        }
22	)*
23    }
24}
25
26generate_aligned_types!(
27    T0(1),
28    T1(2),
29    T2(4),
30    T3(8),
31    T4(16),
32    T5(32),
33    T6(64),
34    T7(128),
35    T8(256),
36    T9(512),
37    T10(1024),
38    T11(2048),
39    T12(4096),
40    T13(8192),
41    T14(16384),
42    T15(32768),
43    T16(65536),
44    T17(131072),
45    T18(262144),
46    T19(524288),
47    T20(1048576),
48    T21(2097152),
49    T22(4194304),
50    T23(8388608),
51    T24(16777216),
52    T25(33554432),
53    T26(67108864),
54    T27(134217728),
55    T28(268435456),
56    T29(536870912),
57);
58
59#[macro_export]
60macro_rules! eval_align {
61    // To the best of my understanding:
62    // Some operations will fail because some std algorithms will rely on the
63    // stack, which may not be large enough to accomodate for large alignments.
64    // The program will panic when attempting to use types with very large alignments.
65    (limited_stack, $a:expr; $fn:ident ::<_ $(,$params:ident)*>($($args:expr),*) ) => {
66	match $a {
67	    1         => $fn::<T0, $($params,)*>($($args,)*),
68	    2         => $fn::<T1, $($params,)*>($($args,)*),
69	    4         => $fn::<T2, $($params,)*>($($args,)*),
70	    8         => $fn::<T3, $($params,)*>($($args,)*),
71	    16        => $fn::<T4, $($params,)*>($($args,)*),
72	    32        => $fn::<T5, $($params,)*>($($args,)*),
73	    64        => $fn::<T6, $($params,)*>($($args,)*),
74	    128       => $fn::<T7, $($params,)*>($($args,)*),
75	    256       => $fn::<T8, $($params,)*>($($args,)*),
76	    512       => $fn::<T9, $($params,)*>($($args,)*),
77	    1024      => $fn::<T10, $($params,)*>($($args,)*),
78	    2048      => $fn::<T11, $($params,)*>($($args,)*),
79	    4096      => $fn::<T12, $($params,)*>($($args,)*),
80	    8192      => $fn::<T13, $($params,)*>($($args,)*),
81	    a => unreachable!("Alignment is too large ({}) for vector manipulations", a)
82	}
83    };
84
85    // Other algorithms seem to work fine even with large alignments.
86    ($a:expr; $fn:ident ::<_ $(,$params:ident)*>($($args:expr),*) ) => {
87	match $a {
88	    1         => $fn::<T0, $($params,)*>($($args,)*),
89	    2         => $fn::<T1, $($params,)*>($($args,)*),
90	    4         => $fn::<T2, $($params,)*>($($args,)*),
91	    8         => $fn::<T3, $($params,)*>($($args,)*),
92	    16        => $fn::<T4, $($params,)*>($($args,)*),
93	    32        => $fn::<T5, $($params,)*>($($args,)*),
94	    64        => $fn::<T6, $($params,)*>($($args,)*),
95	    128       => $fn::<T7, $($params,)*>($($args,)*),
96	    256       => $fn::<T8, $($params,)*>($($args,)*),
97	    512       => $fn::<T9, $($params,)*>($($args,)*),
98	    1024      => $fn::<T10, $($params,)*>($($args,)*),
99	    2048      => $fn::<T11, $($params,)*>($($args,)*),
100	    4096      => $fn::<T12, $($params,)*>($($args,)*),
101	    8192      => $fn::<T13, $($params,)*>($($args,)*),
102	    16384     => $fn::<T14, $($params,)*>($($args,)*),
103	    32768     => $fn::<T15, $($params,)*>($($args,)*),
104	    65536     => $fn::<T16, $($params,)*>($($args,)*),
105	    131072    => $fn::<T17, $($params,)*>($($args,)*),
106	    262144    => $fn::<T18, $($params,)*>($($args,)*),
107	    524288    => $fn::<T19, $($params,)*>($($args,)*),
108	    1048576   => $fn::<T20, $($params,)*>($($args,)*),
109	    2097152   => $fn::<T21, $($params,)*>($($args,)*),
110	    4194304   => $fn::<T22, $($params,)*>($($args,)*),
111	    8388608   => $fn::<T23, $($params,)*>($($args,)*),
112	    16777216  => $fn::<T24, $($params,)*>($($args,)*),
113	    33554432  => $fn::<T25, $($params,)*>($($args,)*),
114	    67108864  => $fn::<T26, $($params,)*>($($args,)*),
115	    134217728 => $fn::<T27, $($params,)*>($($args,)*),
116	    268435456 => $fn::<T28, $($params,)*>($($args,)*),
117	    536870912 => $fn::<T29, $($params,)*>($($args,)*),
118	    _ => unreachable!("Unsupported alignment detected")
119	}
120    }
121}
122
123pub trait CopyElem: Any + Copy {}
124impl<T> CopyElem for T where T: Any + Copy {}
125
126#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
127pub struct ElemInfo {
128    /// Type encoding for hiding the type of data from the compiler.
129    pub(crate) type_id: TypeId,
130    /// Number of alignment chunks occupied by an element of this buffer.
131    ///
132    /// The size of the element in bytes is then given by `size * alignment`.
133    pub(crate) size: usize,
134    /// Alignment info for an element stored in this `Vec`.
135    pub(crate) alignment: usize,
136}
137
138impl ElemInfo {
139    #[inline]
140    pub fn new<T: 'static>() -> ElemInfo {
141        ElemInfo {
142            type_id: TypeId::of::<T>(),
143            size: size_of::<T>() / align_of::<T>(),
144            alignment: align_of::<T>(),
145        }
146    }
147
148    #[inline]
149    pub const fn num_bytes(self) -> usize {
150        self.size * self.alignment
151    }
152}
153
154#[cfg(test)]
155mod tests {
156    use super::*;
157
158    #[test]
159    fn info_struct() {
160        let elem_u32 = ElemInfo::new::<u32>();
161        assert_eq!(
162            elem_u32,
163            ElemInfo {
164                type_id: TypeId::of::<u32>(),
165                size: 1,
166                alignment: 4,
167            }
168        );
169
170        assert_eq!(elem_u32.num_bytes(), 4);
171    }
172}