int_conv/extend/
default.rs

1//! Default extension
2
3// Imports
4use crate::{SignExtend, ZeroExtend};
5
6/// Generic extension
7///
8/// This type performs either a zero extend or
9/// a sign extend, depending if the type is signed.
10pub trait Extend<T>: Sized {
11	/// Extends this type
12	fn extend(self) -> T;
13}
14
15/// Extending to the same type simply returns it
16impl<T> Extend<T> for T {
17	#[inline]
18	fn extend(self) -> Self {
19		self
20	}
21}
22
23/// Macro to help implement [`Extend`]
24///
25/// Note: Regardless if `GAT`s are available, a `impl Extend<&'b U> for &'a T` isn't
26///       possible, as it would require memory available for `U` at `T`, which we don't
27///       know from just receiving a reference to `T`.
28macro_rules! impl_extend {
29	($T:ty => $( $U:ty ),+ $(,)? => $method:ident) => {
30		$(
31			impl Extend<$U> for $T
32			{
33				#[inline]
34				fn extend(self) -> $U {
35					self.$method()
36				}
37			}
38
39			// TODO: Replace with generic version once specialization is stable
40			impl<'a> Extend<$U> for &'a $T
41			where
42				$T: Extend<$U>
43			{
44				#[inline]
45				fn extend(self) -> $U {
46					<$T as Extend<$U>>::extend(*self)
47				}
48			}
49		)+
50	};
51}
52
53// Unsigned
54impl_extend! { u8   => u16, u32, u64, u128 => zero_extend }
55impl_extend! { u16  =>      u32, u64, u128 => zero_extend }
56impl_extend! { u32  =>           u64, u128 => zero_extend }
57impl_extend! { u64  =>                u128 => zero_extend }
58
59// Signed
60impl_extend! { i8   => i16, i32, i64, i128 => sign_extend }
61impl_extend! { i16  =>      i32, i64, i128 => sign_extend }
62impl_extend! { i32  =>           i64, i128 => sign_extend }
63impl_extend! { i64  =>                i128 => sign_extend }
64
65/// Helper trait for [`Extend`] to be used with turbofish syntax
66pub trait Extended {
67	/// Extends this type
68	#[inline]
69	fn extended<T>(self) -> T
70	where
71		Self: Extend<T>,
72	{
73		self.extend()
74	}
75}
76impl<T> Extended for T {}
77
78// Check that all `Extend` impls exist
79static_assertions::assert_impl_all! { i8   :     Extend<i8>,     Extend<i16>,     Extend<i32>,     Extend<i64>,     Extend<i128> }
80static_assertions::assert_impl_all! { i16  :                     Extend<i16>,     Extend<i32>,     Extend<i64>,     Extend<i128> }
81static_assertions::assert_impl_all! { i32  :                                      Extend<i32>,     Extend<i64>,     Extend<i128> }
82static_assertions::assert_impl_all! { i64  :                                                       Extend<i64>,     Extend<i128> }
83static_assertions::assert_impl_all! { i128 :                                                                        Extend<i128> }
84static_assertions::assert_impl_all! { u8   :     Extend<u8>,     Extend<u16>,     Extend<u32>,     Extend<u64>,     Extend<u128> }
85static_assertions::assert_impl_all! { u16  :                     Extend<u16>,     Extend<u32>,     Extend<u64>,     Extend<u128> }
86static_assertions::assert_impl_all! { u32  :                                      Extend<u32>,     Extend<u64>,     Extend<u128> }
87static_assertions::assert_impl_all! { u64  :                                                       Extend<u64>,     Extend<u128> }
88static_assertions::assert_impl_all! { u128 :                                                                        Extend<u128> }
89
90#[cfg(test)]
91mod tests {
92	// Imports
93	use super::*;
94	use crate::{SignExtended, ZeroExtended};
95
96	#[test]
97	#[rustfmt::skip]
98	fn extend_unsigned() {
99		assert_eq!( u8::extended::< u16>(1),  u8::zero_extended::< u16>(1));
100		assert_eq!( u8::extended::< u32>(1),  u8::zero_extended::< u32>(1));
101		assert_eq!( u8::extended::< u64>(1),  u8::zero_extended::< u64>(1));
102		assert_eq!( u8::extended::<u128>(1),  u8::zero_extended::<u128>(1));
103		assert_eq!(u16::extended::< u32>(1), u16::zero_extended::< u32>(1));
104		assert_eq!(u16::extended::< u64>(1), u16::zero_extended::< u64>(1));
105		assert_eq!(u16::extended::<u128>(1), u16::zero_extended::<u128>(1));
106		assert_eq!(u32::extended::< u64>(1), u32::zero_extended::< u64>(1));
107		assert_eq!(u32::extended::<u128>(1), u32::zero_extended::<u128>(1));
108		assert_eq!(u64::extended::<u128>(1), u64::zero_extended::<u128>(1));
109	}
110
111	#[test]
112	#[rustfmt::skip]
113	fn extend_unsigned_big() {
114		assert_eq!(  u8::extended::<  u8>(  u8::MAX),   u8::zero_extended::<  u8>(  u8::MAX));
115		assert_eq!(  u8::extended::< u16>(  u8::MAX),   u8::zero_extended::< u16>(  u8::MAX));
116		assert_eq!(  u8::extended::< u32>(  u8::MAX),   u8::zero_extended::< u32>(  u8::MAX));
117		assert_eq!(  u8::extended::< u64>(  u8::MAX),   u8::zero_extended::< u64>(  u8::MAX));
118		assert_eq!(  u8::extended::<u128>(  u8::MAX),   u8::zero_extended::<u128>(  u8::MAX));
119		assert_eq!( u16::extended::< u16>( u16::MAX),  u16::zero_extended::< u16>( u16::MAX));
120		assert_eq!( u16::extended::< u32>( u16::MAX),  u16::zero_extended::< u32>( u16::MAX));
121		assert_eq!( u16::extended::< u64>( u16::MAX),  u16::zero_extended::< u64>( u16::MAX));
122		assert_eq!( u16::extended::<u128>( u16::MAX),  u16::zero_extended::<u128>( u16::MAX));
123		assert_eq!( u32::extended::< u32>( u32::MAX),  u32::zero_extended::< u32>( u32::MAX));
124		assert_eq!( u32::extended::< u64>( u32::MAX),  u32::zero_extended::< u64>( u32::MAX));
125		assert_eq!( u32::extended::<u128>( u32::MAX),  u32::zero_extended::<u128>( u32::MAX));
126		assert_eq!( u64::extended::< u64>( u64::MAX),  u64::zero_extended::< u64>( u64::MAX));
127		assert_eq!( u64::extended::<u128>( u64::MAX),  u64::zero_extended::<u128>( u64::MAX));
128		assert_eq!(u128::extended::<u128>(u128::MAX), u128::zero_extended::<u128>(u128::MAX));
129	}
130
131	#[test]
132	#[rustfmt::skip]
133	fn extend_signed_positive() {
134		assert_eq!( i8::extended::< i16>(1),  i8::sign_extended::< i16>(1));
135		assert_eq!( i8::extended::< i32>(1),  i8::sign_extended::< i32>(1));
136		assert_eq!( i8::extended::< i64>(1),  i8::sign_extended::< i64>(1));
137		assert_eq!( i8::extended::<i128>(1),  i8::sign_extended::<i128>(1));
138		assert_eq!(i16::extended::< i32>(1), i16::sign_extended::< i32>(1));
139		assert_eq!(i16::extended::< i64>(1), i16::sign_extended::< i64>(1));
140		assert_eq!(i16::extended::<i128>(1), i16::sign_extended::<i128>(1));
141		assert_eq!(i32::extended::< i64>(1), i32::sign_extended::< i64>(1));
142		assert_eq!(i32::extended::<i128>(1), i32::sign_extended::<i128>(1));
143		assert_eq!(i64::extended::<i128>(1), i64::sign_extended::<i128>(1));
144	}
145
146	#[test]
147	#[rustfmt::skip]
148	fn extend_signed_negative() {
149		assert_eq!( i8::extended::< i16>(-1),  i8::sign_extended::< i16>(-1));
150		assert_eq!( i8::extended::< i32>(-1),  i8::sign_extended::< i32>(-1));
151		assert_eq!( i8::extended::< i64>(-1),  i8::sign_extended::< i64>(-1));
152		assert_eq!( i8::extended::<i128>(-1),  i8::sign_extended::<i128>(-1));
153		assert_eq!(i16::extended::< i32>(-1), i16::sign_extended::< i32>(-1));
154		assert_eq!(i16::extended::< i64>(-1), i16::sign_extended::< i64>(-1));
155		assert_eq!(i16::extended::<i128>(-1), i16::sign_extended::<i128>(-1));
156		assert_eq!(i32::extended::< i64>(-1), i32::sign_extended::< i64>(-1));
157		assert_eq!(i32::extended::<i128>(-1), i32::sign_extended::<i128>(-1));
158		assert_eq!(i64::extended::<i128>(-1), i64::sign_extended::<i128>(-1));
159	}
160}