1use crate::Signed;
5use core::mem;
6
7pub trait SignExtend<T>: Sized {
12 fn sign_extend(self) -> T;
14}
15
16impl<T> SignExtend<T> for T {
18 #[inline]
19 fn sign_extend(self) -> Self {
20 self
21 }
22}
23
24macro_rules! impl_sign_extend {
30 ($T:ty => $( $U:ty ),+ $(,)?) => {
31 $(
32 ::static_assertions::const_assert!(mem::size_of::<$U>() >= mem::size_of::<$T>());
35
36 impl SignExtend<$U> for $T
37 {
38 #[inline]
39 #[allow(clippy::as_conversions)]
40 fn sign_extend(self) -> $U {
41 self
44 as <$T as Signed>::Signed
45 as <$U as Signed>::Signed
46 as $U
47 }
48 }
49
50 impl<'a> SignExtend<$U> for &'a $T
52 where
53 $T: SignExtend<$U>
54 {
55 #[inline]
56 fn sign_extend(self) -> $U {
57 <$T as SignExtend<$U>>::sign_extend(*self)
58 }
59 }
60 )+
61 };
62}
63
64impl_sign_extend! { i8 => i16, i32, i64, i128 }
66impl_sign_extend! { i16 => i32, i64, i128 }
67impl_sign_extend! { i32 => i64, i128 }
68impl_sign_extend! { i64 => i128 }
69
70pub trait SignExtended {
72 #[inline]
74 fn sign_extended<T>(self) -> T
75 where
76 Self: SignExtend<T>,
77 {
78 self.sign_extend()
79 }
80}
81impl<T> SignExtended for T {}
82
83static_assertions::assert_impl_all! { i8 : SignExtend<i8>, SignExtend<i16>, SignExtend<i32>, SignExtend<i64>, SignExtend<i128> }
85static_assertions::assert_impl_all! { i16 : SignExtend<i16>, SignExtend<i32>, SignExtend<i64>, SignExtend<i128> }
86static_assertions::assert_impl_all! { i32 : SignExtend<i32>, SignExtend<i64>, SignExtend<i128> }
87static_assertions::assert_impl_all! { i64 : SignExtend<i64>, SignExtend<i128> }
88static_assertions::assert_impl_all! { i128 : SignExtend<i128> }
89
90#[cfg(test)]
91mod tests {
92 use super::*;
94
95 #[test]
96 #[rustfmt::skip]
97 fn sign_extend_positive() {
98 assert_eq!(i8 ::sign_extended::< i16>(1), 1);
99 assert_eq!(i8 ::sign_extended::< i32>(1), 1);
100 assert_eq!(i8 ::sign_extended::< i64>(1), 1);
101 assert_eq!(i8 ::sign_extended::<i128>(1), 1);
102 assert_eq!(i16::sign_extended::< i32>(1), 1);
103 assert_eq!(i16::sign_extended::< i64>(1), 1);
104 assert_eq!(i16::sign_extended::<i128>(1), 1);
105 assert_eq!(i32::sign_extended::< i64>(1), 1);
106 assert_eq!(i32::sign_extended::<i128>(1), 1);
107 assert_eq!(i64::sign_extended::<i128>(1), 1);
108 }
109
110 #[test]
111 #[rustfmt::skip]
112 fn sign_extend_negative() {
113 assert_eq!( i8::sign_extended::< i16>(-1), -1);
114 assert_eq!( i8::sign_extended::< i32>(-1), -1);
115 assert_eq!( i8::sign_extended::< i64>(-1), -1);
116 assert_eq!( i8::sign_extended::<i128>(-1), -1);
117 assert_eq!(i16::sign_extended::< i32>(-1), -1);
118 assert_eq!(i16::sign_extended::< i64>(-1), -1);
119 assert_eq!(i16::sign_extended::<i128>(-1), -1);
120 assert_eq!(i32::sign_extended::< i64>(-1), -1);
121 assert_eq!(i32::sign_extended::<i128>(-1), -1);
122 assert_eq!(i64::sign_extended::<i128>(-1), -1);
123 }
124}