devela/num/primitive/
split.rs

1// devela::data::conversion::cast::split
2//
3//! fns to split a primitive into an array of smaller primitives.
4//
5// TOC
6// - trait definition
7// - trait implementation
8// - wrapper implementations
9
10use crate::{paste, Cast};
11
12/// Offers methods to split a primitive into an array of smaller primitives.
13///
14/// See also the [`Cast`] type for the equivalent *const* methods, and the
15/// [`PrimitiveJoin`][super::PrimitiveJoin] trait for the opposite operations.
16pub trait PrimitiveSplit<T, const LEN: usize> {
17    /// Splits `self` into an array of `T` in big-endian order.
18    #[must_use]
19    fn into_array_be(self) -> [T; LEN];
20    /// Splits `self` into an array of `T` in little-endian order.
21    #[must_use]
22    fn into_array_le(self) -> [T; LEN];
23    /// Splits `self` into an array of `T` in native-endian order.
24    #[must_use]
25    fn into_array_ne(self) -> [T; LEN];
26}
27
28// Implements the trait methods
29macro_rules! impl_into_trait {
30    ( $( $P:ident, $T:ident, $LEN:literal );+ $(;)? ) => {
31        $( impl_into_trait![@$P, $T, $LEN]; )+
32    };
33    (@$P:ident, $T:ident, $LEN:literal) => { paste! {
34        impl PrimitiveSplit<$T, $LEN> for $P {
35            fn into_array_be(self) -> [$T; $LEN] { Cast(self).[<into_ $T _be>]() }
36            fn into_array_le(self) -> [$T; $LEN] { Cast(self).[<into_ $T _le>]() }
37            fn into_array_ne(self) -> [$T; $LEN] { Cast(self).[<into_ $T _ne>]() }
38        }
39    }};
40}
41impl_into_trait![
42    u128, u64, 2; u128, u32, 4; u128, u16, 8; u128, u8, 16;
43    u64, u32, 2; u64, u16, 4; u64, u8, 8;
44    u32, u16, 2; u32, u8, 4;
45    u16, u8, 2;
46];
47
48/* implements the Cast wrapper methods */
49
50#[rustfmt::skip]
51#[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "split")))]
52impl Cast<u16> {
53    /// Splits a `u16` into an array of `[u8; 2]` in big-endian order.
54    #[must_use]
55    pub const fn into_u8_be(self) -> [u8; 2] { self.0.to_be_bytes() }
56
57    /// Splits a `u16` into an array of `[u8; 2]` in little-endian order.
58    #[must_use]
59    pub const fn into_u8_le(self) -> [u8; 2] { self.0.to_le_bytes() }
60
61    /// Splits a `u16` into an array of `[u8; 2]` in native-endian order.
62    #[must_use]
63    pub const fn into_u8_ne(self) -> [u8; 2] { self.0.to_ne_bytes() }
64}
65
66#[rustfmt::skip]
67#[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "split")))]
68impl Cast<u32> {
69    /// Splits a `u32` into an array of `[u16; 2]` in big-endian order.
70    #[must_use]
71    pub const fn into_u16_be(self) -> [u16; 2] {
72        let v0: u16 = ((self.0 >> 16) & u16::MAX as u32) as u16;
73        let v1: u16 = (self.0 & u16::MAX as u32) as u16;
74        [v0, v1]
75    }
76
77    /// Splits a `u32` into an array of `[u16; 2]` in little-endian order.
78    #[must_use]
79    pub const fn into_u16_le(self) -> [u16; 2] {
80        let v1: u16 = ((self.0 >> 16) & u16::MAX as u32) as u16;
81        let v0: u16 = (self.0 & u16::MAX as u32) as u16;
82        [v0, v1]
83    }
84
85    /// Splits a `u32` into an array of `[u16; 2]` in native-endian order.
86    #[must_use]
87    pub const fn into_u16_ne(self) -> [u16; 2] {
88        if cfg!(target_endian = "big") {
89            Cast::<u32>::into_u16_be(self)
90        } else {
91            Cast::<u32>::into_u16_le(self)
92        }
93    }
94
95    /// Splits a `u32` into an array of `[u8; 4]` in big-endian order.
96    #[must_use]
97    pub const fn into_u8_be(self) -> [u8; 4] { self.0.to_be_bytes() }
98
99    /// Splits a `u32` into an array of `[u8; 4]` in little-endian order.
100    #[must_use]
101    pub const fn into_u8_le(self) -> [u8; 4] { self.0.to_le_bytes() }
102
103    /// Splits a `u32` into an array of `[u8; 4]` in native-endian order.
104    #[must_use]
105    pub const fn into_u8_ne(self) -> [u8; 4] { self.0.to_ne_bytes() }
106}
107
108#[rustfmt::skip]
109#[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "split")))]
110impl Cast<u64> {
111    /// Splits a `u64` into an array of `[u32; 2]` in big-endian order.
112    #[must_use]
113    pub const fn into_u32_be(self) -> [u32; 2] {
114        let v0: u32 = ((self.0 >> 32) & u32::MAX as u64) as u32;
115        let v1: u32 = (self.0 & u32::MAX as u64) as u32;
116        [v0, v1]
117    }
118
119    /// Splits a `u64` into an array of `[u32; 2]` in little-endian order.
120    #[must_use]
121    pub const fn into_u32_le(self) -> [u32; 2] {
122        let v1: u32 = ((self.0 >> 32) & u32::MAX as u64) as u32;
123        let v0: u32 = (self.0 & u32::MAX as u64) as u32;
124        [v0, v1]
125    }
126
127    /// Splits a `u64` into an array of `[u32; 2]` in native-endian order.
128    #[must_use]
129    pub const fn into_u32_ne(self) -> [u32; 2] {
130        if cfg!(target_endian = "big") {
131            Cast::<u64>::into_u32_be(self)
132        } else {
133            Cast::<u64>::into_u32_le(self)
134        }
135    }
136
137    /// Splits a `u64` into an array of `[u16; 4]` in big-endian order.
138    #[must_use]
139    pub const fn into_u16_be(self) -> [u16; 4] {
140        let v0: u16 = ((self.0 >> (16 * 3)) & u16::MAX as u64) as u16;
141        let v1: u16 = ((self.0 >> (16 * 2)) & u16::MAX as u64) as u16;
142        let v2: u16 = ((self.0 >> 16) & u16::MAX as u64) as u16;
143        let v3: u16 = (self.0 & u16::MAX as u64) as u16;
144        [v0, v1, v2, v3]
145    }
146
147    /// Splits a `u64` into an array of `[u16; 4]` in little-endian order.
148    #[must_use]
149    pub const fn into_u16_le(self) -> [u16; 4] {
150        let v3: u16 = ((self.0 >> (16 * 3)) & u16::MAX as u64) as u16;
151        let v2: u16 = ((self.0 >> (16 * 2)) & u16::MAX as u64) as u16;
152        let v1: u16 = ((self.0 >> 16) & u16::MAX as u64) as u16;
153        let v0: u16 = (self.0 & u16::MAX as u64) as u16;
154        [v0, v1, v2, v3]
155    }
156
157    /// Splits a `u64` into an array of `[u16; 4]` in native-endian order.
158    #[must_use]
159    pub const fn into_u16_ne(self) -> [u16; 4] {
160        if cfg!(target_endian = "big") {
161            Cast::<u64>::into_u16_be(self)
162        } else {
163            Cast::<u64>::into_u16_le(self)
164        }
165    }
166
167    /// Splits a `u64` into an array of `[u8; 8]` in big-endian order.
168    #[must_use]
169    pub const fn into_u8_be(self) -> [u8; 8] { self.0.to_be_bytes() }
170
171    /// Splits a `u64` into an array of `[u8; 8]` in little-endian order.
172    #[must_use]
173    pub const fn into_u8_le(self) -> [u8; 8] { self.0.to_le_bytes() }
174
175    /// Splits a `u64` into an array of `[u8; 8]` in native-endian order.
176    #[must_use]
177    pub const fn into_u8_ne(self) -> [u8; 8] {
178        if cfg!(target_endian = "big") {
179            Cast::<u64>::into_u8_be(self)
180        } else {
181            Cast::<u64>::into_u8_le(self)
182        }
183    }
184}
185
186#[rustfmt::skip]
187#[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "split")))]
188impl Cast<u128> {
189    /// Splits a `u128` into an array of `[u64; 2]` in big-endian order.
190    #[must_use]
191    pub const fn into_u64_be(self) -> [u64; 2] {
192        let v0: u64 = (self.0 >> 64) as u64;
193        let v1: u64 = (self.0 & u64::MAX as u128) as u64;
194        [v0, v1]
195    }
196
197    /// Splits a `u128` into an array of `[u64; 2]` in little-endian order.
198    #[must_use]
199    pub const fn into_u64_le(self) -> [u64; 2] {
200        let v1: u64 = (self.0 >> 64) as u64;
201        let v0: u64 = (self.0 & u64::MAX as u128) as u64;
202        [v0, v1]
203    }
204
205    /// Splits a `u128` into an array of `[u64; 2]` in native-endian order.
206    #[must_use]
207    pub const fn into_u64_ne(self) -> [u64; 2] {
208        if cfg!(target_endian = "big") {
209            Cast::<u128>::into_u64_be(self)
210        } else {
211            Cast::<u128>::into_u64_le(self)
212        }
213    }
214
215    /// Splits a `u128` into an array of `[u32; 4]` in big-endian order.
216    #[must_use]
217    pub const fn into_u32_be(self) -> [u32; 4] {
218        let v0: u32 = (self.0 >> (32 * 3)) as u32;
219        let v1: u32 = ((self.0 >> (32 * 2)) & u32::MAX as u128) as u32;
220        let v2: u32 = ((self.0 >> 32) & u32::MAX as u128) as u32;
221        let v3: u32 = (self.0 & u32::MAX as u128) as u32;
222        [v0, v1, v2, v3]
223    }
224
225    /// Splits a `u128` into an array of `[u32; 4]` in little-endian order.
226    #[must_use]
227    pub const fn into_u32_le(self) -> [u32; 4] {
228        let v3: u32 = (self.0 >> (32 * 3)) as u32;
229        let v2: u32 = ((self.0 >> (32 * 2)) & u32::MAX as u128) as u32;
230        let v1: u32 = ((self.0 >> 32) & u32::MAX as u128) as u32;
231        let v0: u32 = (self.0 & u32::MAX as u128) as u32;
232        [v0, v1, v2, v3]
233    }
234
235    /// Splits a `u128` into an array of `[u32; 4]` in native-endian order.
236    #[must_use]
237    pub const fn into_u32_ne(self) -> [u32; 4] {
238        if cfg!(target_endian = "big") {
239            Cast::<u128>::into_u32_be(self)
240        } else {
241            Cast::<u128>::into_u32_le(self)
242        }
243    }
244
245    /// Splits a `u128` into an array of `[u16; 8]` in big-endian order.
246    #[must_use]
247    pub const fn into_u16_be(self) -> [u16; 8] {
248        let v0: u16 = (self.0 >> (16 * 7)) as u16;
249        let v1: u16 = ((self.0 >> (16 * 6)) & u16::MAX as u128) as u16;
250        let v2: u16 = ((self.0 >> (16 * 5)) & u16::MAX as u128) as u16;
251        let v3: u16 = ((self.0 >> (16 * 4)) & u16::MAX as u128) as u16;
252        let v4: u16 = ((self.0 >> (16 * 3)) & u16::MAX as u128) as u16;
253        let v5: u16 = ((self.0 >> (16 * 2)) & u16::MAX as u128) as u16;
254        let v6: u16 = ((self.0 >> 16) & u16::MAX as u128) as u16;
255        let v7: u16 = (self.0 & u16::MAX as u128) as u16;
256        [v0, v1, v2, v3, v4, v5, v6, v7]
257    }
258
259    /// Splits a `u128` into an array of `[u16; 8]` in little-endian order.
260    #[must_use]
261    pub const fn into_u16_le(self) -> [u16; 8] {
262        let v7: u16 = (self.0 >> (16 * 7)) as u16;
263        let v6: u16 = ((self.0 >> (16 * 6)) & u16::MAX as u128) as u16;
264        let v5: u16 = ((self.0 >> (16 * 5)) & u16::MAX as u128) as u16;
265        let v4: u16 = ((self.0 >> (16 * 4)) & u16::MAX as u128) as u16;
266        let v3: u16 = ((self.0 >> (16 * 3)) & u16::MAX as u128) as u16;
267        let v2: u16 = ((self.0 >> (16 * 2)) & u16::MAX as u128) as u16;
268        let v1: u16 = ((self.0 >> 16) & u16::MAX as u128) as u16;
269        let v0: u16 = (self.0 & u16::MAX as u128) as u16;
270        [v0, v1, v2, v3, v4, v5, v6, v7]
271    }
272
273    /// Splits a `u128` into an array of `[u16; 8]` in native-endian order.
274    #[must_use]
275    pub const fn into_u16_ne(self) -> [u16; 8] {
276        if cfg!(target_endian = "big") {
277            Cast::<u128>::into_u16_be(self)
278        } else {
279            Cast::<u128>::into_u16_le(self)
280        }
281    }
282
283    /// Splits a `u128` into an array of `[u8; 16]` in big-endian order.
284    #[must_use]
285    pub const fn into_u8_be(self) -> [u8; 16] { self.0.to_be_bytes() }
286
287    /// Splits a `u128` into an array of `[u8; 16]` in little-endian order.
288    #[must_use]
289    pub const fn into_u8_le(self) -> [u8; 16] { self.0.to_le_bytes() }
290
291    /// Splits a `u128` into an array of `[u8; 16]` in native-endian order.
292    #[must_use]
293    pub const fn into_u8_ne(self) -> [u8; 16] { self.0.to_ne_bytes() }
294}