1use super::{Truncate, ZeroExtend};
8use core::{
9 mem,
10 ops::{Shl, Shr},
11};
12
13pub trait Split: Sized {
15 type Hi;
17
18 type Lo;
20
21 fn hi(self) -> Self::Hi;
23
24 fn lo(self) -> Self::Lo;
26
27 fn lo_hi(self) -> (Self::Lo, Self::Hi);
29}
30
31pub trait Join: Split {
33 fn join(lo: <Self as Split>::Lo, hi: <Self as Split>::Lo) -> Self;
35}
36
37macro_rules! impl_split_join {
45 ($T:ty => $Hi:ty : $Lo:ty) => {
46 ::static_assertions::assert_eq_size!($T, ($Lo, $Hi));
48
49 impl Split for $T {
50 type Hi = $Hi;
51 type Lo = $Lo;
52
53 #[inline]
54 fn lo(self) -> Self::Lo {
55 <Self as Truncate<Self::Lo>>::truncate(self)
56 }
57
58 #[inline]
59 fn hi(self) -> Self::Hi {
60 <Self as Truncate<Self::Lo>>::truncate(self.shr(8 * mem::size_of::<Self::Lo>()))
61 }
62
63 #[inline]
64 fn lo_hi(self) -> (Self::Lo, Self::Hi) {
65 let lo = self.lo();
66 let hi = self.hi();
67 (lo, hi)
68 }
69 }
70
71 impl Join for $T {
72 #[inline]
73 fn join(lo: <Self as Split>::Lo, hi: <Self as Split>::Lo) -> Self {
74 <$Hi as ZeroExtend<$T>>::zero_extend(hi).shl(8 * mem::size_of::<Self::Lo>()) | <$Lo as ZeroExtend<$T>>::zero_extend(lo)
75 }
76 }
77 };
78}
79
80impl_split_join! { u128 => u64 : u64 }
82impl_split_join! { u64 => u32 : u32 }
83impl_split_join! { u32 => u16 : u16 }
84impl_split_join! { u16 => u8 : u8 }
85
86static_assertions::assert_impl_all! { u16 : Split, Join }
99static_assertions::assert_impl_all! { u32 : Split, Join }
100static_assertions::assert_impl_all! { u64 : Split, Join }
101static_assertions::assert_impl_all! { u128 : Split, Join }
102
103static_assertions::assert_type_eq_all! { <u16 as Split>::Lo, <u16 as Split>::Hi, u8 }
109static_assertions::assert_type_eq_all! { <u32 as Split>::Lo, <u32 as Split>::Hi, u16 }
110static_assertions::assert_type_eq_all! { <u64 as Split>::Lo, <u64 as Split>::Hi, u32 }
111static_assertions::assert_type_eq_all! { <u128 as Split>::Lo, <u128 as Split>::Hi, u64 }
112
113#[cfg(test)]
114mod tests {
115 use super::*;
116
117 #[test]
118 #[rustfmt::skip]
119 fn split_lo() {
120 assert_eq!(u128::lo(u128::MAX), u64::MAX);
121 assert_eq!( u64::lo( u64::MAX), u32::MAX);
122 assert_eq!( u32::lo( u32::MAX), u16::MAX);
123 assert_eq!( u16::lo( u16::MAX), u8::MAX);
124 }
125
126 #[test]
127 #[rustfmt::skip]
128 fn split_lo_half() {
129 assert_eq!(u128::lo(u128::from(u64::MAX)), u64::MAX);
130 assert_eq!( u64::lo( u64::from(u32::MAX)), u32::MAX);
131 assert_eq!( u32::lo( u32::from(u16::MAX)), u16::MAX);
132 assert_eq!( u16::lo( u16::from( u8::MAX)), u8::MAX);
133 }
134
135 #[test]
136 #[rustfmt::skip]
137 fn split_hi() {
138 assert_eq!(u128::hi(u128::MAX), u64::MAX);
139 assert_eq!( u64::hi( u64::MAX), u32::MAX);
140 assert_eq!( u32::hi( u32::MAX), u16::MAX);
141 assert_eq!( u16::hi( u16::MAX), u8::MAX);
142 }
143
144 #[test]
145 #[rustfmt::skip]
146 fn split_hi_half() {
147 assert_eq!(u128::hi(u128::from(u64::MAX)), 0);
148 assert_eq!( u64::hi( u64::from(u32::MAX)), 0);
149 assert_eq!( u32::hi( u32::from(u16::MAX)), 0);
150 assert_eq!( u16::hi( u16::from( u8::MAX)), 0);
151 }
152
153 #[test]
154 #[rustfmt::skip]
155 fn split_lo_hi() {
156 assert_eq!(u128::lo_hi(u128::MAX), (u128::lo(u128::MAX), u128::hi(u128::MAX)));
157 assert_eq!( u64::lo_hi( u64::MAX), ( u64::lo( u64::MAX), u64::hi( u64::MAX)));
158 assert_eq!( u32::lo_hi( u32::MAX), ( u32::lo( u32::MAX), u32::hi( u32::MAX)));
159 assert_eq!( u16::lo_hi( u16::MAX), ( u16::lo( u16::MAX), u16::hi( u16::MAX)));
160 }
161
162 #[test]
163 #[rustfmt::skip]
164 fn split_lo_hi_half() {
165 assert_eq!(u128::lo_hi(u128::from(u64::MAX)), (u128::lo(u128::from(u64::MAX)), u128::hi(u128::from(u64::MAX))));
166 assert_eq!( u64::lo_hi( u64::from(u32::MAX)), ( u64::lo( u64::from(u32::MAX)), u64::hi( u64::from(u32::MAX))));
167 assert_eq!( u32::lo_hi( u32::from(u16::MAX)), ( u32::lo( u32::from(u16::MAX)), u32::hi( u32::from(u16::MAX))));
168 assert_eq!( u16::lo_hi( u16::from( u8::MAX)), ( u16::lo( u16::from( u8::MAX)), u16::hi( u16::from( u8::MAX))));
169 }
170}