devela/num/primitive/
join.rs

1// devela::data::conversion::cast::join
2//
3//! construct an unsigned primitive by joining an array of smaller unsigned primitives.
4//
5// TOC
6// - trait definition
7// - trait implementation
8// - wrapper implementations
9
10use crate::{paste, Cast};
11
12/// Offers methods to construct a primitive from an array or slice of smaller primitives.
13///
14/// Methods expecting an array are more efficient than the ones expecting an
15/// slice. On the other hand slices of any lenght are supported as follows:
16/// - If the slice contains fewer elements than required, the method will
17///   fill in the missing values with zeros.
18/// - If the slice contains more elements than required, the method will
19///   ignore the extra elements.
20///
21/// See also the [`Cast`] type for the equivalent *const* methods, and the
22/// [`PrimitiveSplit`][super::PrimitiveSplit] trait for the opposite operations.
23pub trait PrimitiveJoin<T, U, const LEN: usize> {
24    /// Constructs a primitive `T` from an array of `U` in big-endian order.
25    #[must_use]
26    fn from_array_be(values: [U; LEN]) -> T;
27    /// Constructs a primitive `T` from an array of `U` in little-endian order.
28    #[must_use]
29    fn from_array_le(values: [U; LEN]) -> T;
30    /// Constructs a primitive `T` from an array of `U` in native-endian order.
31    #[must_use]
32    fn from_array_ne(values: [U; LEN]) -> T;
33
34    /// Constructs a primitive `T` from a slice of `U` in big-endian order.
35    #[must_use]
36    fn from_slice_be(values: &[U]) -> T;
37    /// Constructs a primitive `T` from a slice of `U` in little-endian order.
38    #[must_use]
39    fn from_slice_le(values: &[U]) -> T;
40    /// Constructs a primitive `T` from a slice of `U` in native-endian order.
41    #[must_use]
42    fn from_slice_ne(values: &[U]) -> T;
43}
44
45/// Implements the trait methods.
46macro_rules! impl_from_trait {
47    ( $( $T:ident, $U:ident, $LEN:literal );+ $(;)? ) => {
48        $( impl_from_trait![@$T, $U, $LEN]; )+
49    };
50    (@$T:ident, $U:ident, $LEN:literal) => { paste! {
51        impl PrimitiveJoin<$T, $U, $LEN> for $T {
52            fn from_array_be(values: [$U; $LEN]) -> $T { Cast::<$T>::[<from_ $U _be>](values) }
53            fn from_array_le(values: [$U; $LEN]) -> $T { Cast::<$T>::[<from_ $U _le>](values) }
54            fn from_array_ne(values: [$U; $LEN]) -> $T { Cast::<$T>::[<from_ $U _ne>](values) }
55            fn from_slice_be(values: &[$U]) -> $T {
56                let mut array = [0; $LEN];
57                for (i, &v) in values.iter().enumerate() {
58                    array[i] = v;
59                }
60                Cast::<$T>::[<from_ $U _be>](array)
61            }
62            fn from_slice_le(values: &[$U]) -> $T {
63                let mut array = [0; $LEN];
64                for (i, &v) in values.iter().enumerate() {
65                    array[i] = v;
66                }
67                Cast::<$T>::[<from_ $U _le>](array)
68            }
69            fn from_slice_ne(values: &[$U]) -> $T {
70                let mut array = [0; $LEN];
71                for (i, &v) in values.iter().enumerate() {
72                    array[i] = v;
73                }
74                Cast::<$T>::[<from_ $U _ne>](array)
75            }
76        }
77    }};
78}
79impl_from_trait![
80    u128, u64, 2; u128, u32, 4; u128, u16, 8; u128, u8, 16;
81    u64, u32, 2; u64, u16, 4; u64, u8, 8;
82    u32, u16, 2; u32, u8, 4;
83    u16, u8, 2;
84];
85
86/* implements the Cast wrapper methods */
87
88#[rustfmt::skip]
89#[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "join")))]
90impl Cast<u16> {
91    /// Constructs a `u16` from an array of `[u8; 2]` in big-endian order.
92    #[must_use]
93    pub const fn from_u8_be(v: [u8; 2]) -> u16 { u16::from_be_bytes(v) }
94
95    /// Constructs a `u16` from an array of `[u8; 2]` in little-endian order.
96    #[must_use]
97    pub const fn from_u8_le(v: [u8; 2]) -> u16 { u16::from_le_bytes(v) }
98
99    /// Constructs a `u16` from an array of `[u8; 2]` in native-endian order.
100    #[must_use]
101    pub const fn from_u8_ne(v: [u8; 2]) -> u16 { u16::from_ne_bytes(v) }
102}
103
104#[rustfmt::skip]
105#[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "join")))]
106impl Cast<u32> {
107    /// Constructs a `u32` from an array of `[u16; 2]` in big-endian order.
108    #[must_use]
109    pub const fn from_u16_be(v: [u16; 2]) -> u32 {
110        ((v[0] as u32) << 16) | (v[1] as u32)
111    }
112
113    /// Constructs a `u32` from an array of `[u16; 2]` in little-endian order.
114    #[must_use]
115    pub const fn from_u16_le(v: [u16; 2]) -> u32 {
116        ((v[1] as u32) << 16) | (v[0] as u32)
117    }
118
119    /// Constructs a `u32` from an array of `[u16; 2]` in native-endian order.
120    #[must_use]
121    pub const fn from_u16_ne(v: [u16; 2]) -> u32 {
122        if cfg!(target_endian = "big") {
123            Cast::<u32>::from_u16_be(v)
124        } else {
125            Cast::<u32>::from_u16_le(v)
126        }
127    }
128
129    /// Constructs a `u32` from an array of `[u8; 4]` in big-endian order.
130    #[must_use]
131    pub const fn from_u8_be(v: [u8; 4]) -> u32 { u32::from_be_bytes(v) }
132
133    /// Constructs a `u32` from an array of `[u8; 4]` in little-endian order.
134    #[must_use]
135    pub const fn from_u8_le(v: [u8; 4]) -> u32 { u32::from_le_bytes(v) }
136
137    /// Constructs a `u32` from an array of `[u8; 4]` in native-endian order.
138    #[must_use]
139    pub const fn from_u8_ne(v: [u8; 4]) -> u32 { u32::from_ne_bytes(v) }
140}
141
142#[rustfmt::skip]
143#[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "join")))]
144impl Cast<u64> {
145    /// Constructs a `u64` from an array of `[u32; 2]` in big-endian order.
146    #[must_use]
147    pub const fn from_u32_be(v: [u32; 2]) -> u64 {
148        ((v[0] as u64) << 32) | (v[1] as u64)
149    }
150
151    /// Constructs a `u64` from an array of `[u32; 2]` in little-endian order.
152    #[must_use]
153    pub const fn from_u32_le(v: [u32; 2]) -> u64 {
154        ((v[1] as u64) << 32) | (v[0] as u64)
155    }
156
157    /// Constructs a `u64` from an array of `[u32; 2]` in native-endian order.
158    #[must_use]
159    pub const fn from_u32_ne(v: [u32; 2]) -> u64 {
160        if cfg!(target_endian = "big") {
161            Cast::<u64>::from_u32_be(v)
162        } else {
163            Cast::<u64>::from_u32_le(v)
164        }
165    }
166
167    /// Constructs a `u64` from an array of `[u16; 4]` in big-endian order.
168    #[must_use]
169    pub const fn from_u16_be(v: [u16; 4]) -> u64 {
170        ((v[0] as u64) << (16 * 3))
171            | ((v[1] as u64) << (16 * 2))
172            | ((v[2] as u64) << 16)
173            | (v[3] as u64)
174    }
175
176    /// Constructs a `u64` from an array of `[u16; 4]` in little-endian order.
177    #[must_use]
178    pub const fn from_u16_le(v: [u16; 4]) -> u64 {
179        ((v[3] as u64) << (16 * 3))
180            | ((v[2] as u64) << (16 * 2))
181            | ((v[1] as u64) << 16)
182            | (v[0] as u64)
183    }
184
185    /// Constructs a `u64` from an array of `[u16; 4]` in native-endian order.
186    #[must_use]
187    pub const fn from_u16_ne(v: [u16; 4]) -> u64 {
188        if cfg!(target_endian = "big") {
189            Cast::<u64>::from_u16_be(v)
190        } else {
191            Cast::<u64>::from_u16_le(v)
192        }
193    }
194
195    /// Constructs a `u64` from an array of `[u8; 8]` in big-endian order.
196    #[must_use]
197    pub const fn from_u8_be(v: [u8; 8]) -> u64 { u64::from_be_bytes(v) }
198
199    /// Constructs a `u64` from an array of `[u8; 8]` in little-endian order.
200    #[must_use]
201    pub const fn from_u8_le(v: [u8; 8]) -> u64 { u64::from_le_bytes(v) }
202
203    /// Constructs a `u64` from an array of `[u8; 8]` in native-endian order.
204    #[must_use]
205    pub const fn from_u8_ne(v: [u8; 8]) -> u64 { u64::from_ne_bytes(v) }
206}
207
208#[rustfmt::skip]
209#[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "join")))]
210impl Cast<u128> {
211    /// Constructs a `u128` from an array of `[u64; 2]` in big-endian order.
212    #[must_use]
213    pub const fn from_u64_be(v: [u64; 2]) -> u128 {
214        ((v[0] as u128) << 64) | (v[1] as u128)
215    }
216
217    /// Constructs a `u128` from an array of `[u64; 2]` in little-endian order.
218    #[must_use]
219    pub const fn from_u64_le(v: [u64; 2]) -> u128 {
220        ((v[1] as u128) << 64) | (v[0] as u128)
221    }
222
223    /// Constructs a `u128` from an array of `[u64; 2]` in native-endian order.
224    #[must_use]
225    pub const fn from_u64_ne(v: [u64; 2]) -> u128 {
226        if cfg!(target_endian = "big") {
227            Cast::<u128>::from_u64_be(v)
228        } else {
229            Cast::<u128>::from_u64_le(v)
230        }
231    }
232
233    /// Constructs a `u128` from an array of `[u32; 4]` in big-endian order.
234    #[must_use]
235    pub const fn from_u32_be(v: [u32; 4]) -> u128 {
236        ((v[0] as u128) << (32 * 3))
237            | ((v[1] as u128) << (32 * 2))
238            | ((v[2] as u128) << 32)
239            | (v[3] as u128)
240    }
241
242    /// Constructs a `u128` from an array of `[u32; 4]` in little-endian order.
243    #[must_use]
244    pub const fn from_u32_le(v: [u32; 4]) -> u128 {
245        ((v[3] as u128) << (32 * 3))
246            | ((v[2] as u128) << (32 * 2))
247            | ((v[1] as u128) << 32)
248            | (v[0] as u128)
249    }
250
251    /// Constructs a `u128` from an array of `[u32; 4]` in native-endian order.
252    #[must_use]
253    pub const fn from_u32_ne(v: [u32; 4]) -> u128 {
254        if cfg!(target_endian = "big") {
255            Cast::<u128>::from_u32_be(v)
256        } else {
257            Cast::<u128>::from_u32_le(v)
258        }
259    }
260
261    /// Constructs a `u128` from an array of `[u16; 8]` in big-endian order.
262    #[must_use]
263    pub const fn from_u16_be(v: [u16; 8]) -> u128 {
264        ((v[0] as u128) << (16 * 7))
265            | ((v[1] as u128) << (16 * 6))
266            | ((v[2] as u128) << (16 * 5))
267            | ((v[3] as u128) << (16 * 4))
268            | ((v[4] as u128) << (16 * 3))
269            | ((v[5] as u128) << (16 * 2))
270            | ((v[6] as u128) << 16)
271            | (v[7] as u128)
272    }
273
274    /// Constructs a `u128` from an array of `[u16; 8]` in little-endian order.
275    #[must_use]
276    pub const fn from_u16_le(v: [u16; 8]) -> u128 {
277        ((v[7] as u128) << (16 * 7))
278            | ((v[6] as u128) << (16 * 6))
279            | ((v[5] as u128) << (16 * 5))
280            | ((v[4] as u128) << (16 * 4))
281            | ((v[3] as u128) << (16 * 3))
282            | ((v[2] as u128) << (16 * 2))
283            | ((v[1] as u128) << 16)
284            | (v[0] as u128)
285    }
286
287    /// Constructs a `u128` from an array of `[u16; 8]` in native-endian order.
288    #[must_use]
289    pub const fn from_u16_ne(v: [u16; 8]) -> u128 {
290        if cfg!(target_endian = "big") {
291            Cast::<u128>::from_u16_be(v)
292        } else {
293            Cast::<u128>::from_u16_le(v)
294        }
295    }
296
297    /// Constructs a `u128` from an array of `[u8; 16]` in big-endian order.
298    #[must_use]
299    pub const fn from_u8_be(v: [u8; 16]) -> u128 { u128::from_be_bytes(v) }
300
301    /// Constructs a `u128` from an array of `[u8; 16]` in little-endian order.
302    #[must_use]
303    pub const fn from_u8_le(v: [u8; 16]) -> u128 { u128::from_le_bytes(v) }
304
305    /// Constructs a `u128` from an array of `[u8; 16]` in native-endian order.
306    #[must_use]
307    pub const fn from_u8_ne(v: [u8; 16]) -> u128 { u128::from_ne_bytes(v) }
308}