1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
use core::num::Wrapping;

pub trait Cast<T> {
    /// # Example
    /// ```
    /// use cast_trait::Cast;
    /// use std::num::Wrapping;
    ///
    /// assert_eq!(Cast::<isize>::cast(2_usize) * 2_isize, 4_isize);
    /// assert_eq!(Cast::<f32>::cast(2_u32) * 2_f32, 4_f32);
    /// assert_eq!(Cast::<bool>::cast(1_u32), true);
    /// assert_eq!(Cast::<f32>::cast(false), 0_f32);
    /// assert_eq!(Cast::<usize>::cast(true), 1_usize);
    /// assert_eq!(
    ///     Cast::<Wrapping<usize>>::cast(Wrapping(1.0)),
    ///     Wrapping(1_usize)
    /// );
    /// ```
    fn cast(self) -> T;
}

macro_rules! impl_cast {
    ($F:ty, $($T:ty),*) => ($(
        impl Cast<$T> for $F {
            #[inline(always)]
            fn cast(self) -> $T {
                self as $T
            }
        }
    )*);
}

macro_rules! impl_cast_primitive {
    ($($F:ty),*) => (
        $(
            impl_cast!(
                $F,
                i8, i16, i32, i64, isize, u8, u16, u32, u64, usize, f32, f64
            );
            #[cfg(feature = "nightly")]
            impl_cast!(
                $F,
                i128, u128
            );
        )*
    );
}

impl_cast_primitive!(i8, i16, i32, i64, isize, u8, u16, u32, u64, usize, f32, f64);

#[cfg(feature = "nightly")]
impl_cast_primitive!(i128, u128);

macro_rules! impl_cast_bool {
    (int, $($T:ty),*) => (
        $(
            impl Cast<$T> for bool {
                #[inline(always)]
                fn cast(self) -> $T {
                    if self {1} else {0}
                }
            }
            impl Cast<bool> for $T {
                #[inline(always)]
                fn cast(self) -> bool {
                    if self == 0 {false} else {true}
                }
            }
        )*
    );
    (float, $($T:ty),*) => (
        $(
            impl Cast<$T> for bool {
                #[inline(always)]
                fn cast(self) -> $T {
                    if self {1.0} else {0.0}
                }
            }
            impl Cast<bool> for $T {
                #[inline(always)]
                fn cast(self) -> bool {
                    if self == 0.0 {false} else {true}
                }
            }
        )*
    );
}

impl_cast_bool!(int, i8, i16, i32, i64, isize, u8, u16, u32, u64, usize);
impl_cast_bool!(float, f32, f64);

#[cfg(feature = "nightly")]
impl_cast_bool!(int, i128, u128);

impl<A, B> Cast<Wrapping<B>> for Wrapping<A>
where
    A: Cast<B>,
{
    #[inline(always)]
    fn cast(self) -> Wrapping<B> {
        Wrapping(Cast::cast(self.0))
    }
}

macro_rules! reverse {
    ($self:ident [] $($reversed:expr),+) => (
        [$($reversed),+]
    );
    ($self:ident []) => ([]);
    ($self:ident [$first:expr]) => (
        reverse!($self [] $crate::Cast::cast($self[$first].clone()))
    );
    ($self:ident [$first:expr, $($rest:expr),+]) => (
        reverse!($self [$($rest),+] $crate::Cast::cast($self[$first].clone()))
    );
    ($self:ident [$first:expr] $($reversed:expr),+) => (
        reverse!($self [] $crate::Cast::cast($self[$first].clone()), $($reversed),+)
    );
    ($self:ident [$first:expr, $($rest:expr),+] $($reversed:expr),+) => (
        reverse!($self [$($rest),+] $crate::Cast::cast($self[$first].clone()), $($reversed),+)
    );
}

macro_rules! count_args {
    () => { 0 };
    ($x:expr) => { 1 };
    ($x:expr, $($y:expr),+) => { 1 + count_args!($($y),+) };
}

macro_rules! impl_cast_slice {
    ($($x:expr),+) => (
        impl<A, B> Cast<[B; count_args!($($x),+)]> for [A; count_args!($($x),+)]
        where
            A: Clone + Cast<B>,
        {
            #[inline]
            fn cast(self) -> [B; count_args!($($x),+)] {
                reverse!(self [$($x),+])
            }
        }
    );
}

macro_rules! impl_cast_slices {
    () => ();
    ($x:expr) => (
        impl_cast_slice!($x);
    );
    ($x:expr, $($y:expr),+) => (
        impl_cast_slice!($x, $($y),+);
        impl_cast_slices!($($y),+);
    );
}

#[cfg_attr(rustfmt, rustfmt_skip)]
impl_cast_slices!(
    31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
);

#[test]
fn test_cast_slice() {
    let mut x: [i32; 32] = [0_i32; 32];

    for i in 0..32 {
        x[i] = i as i32;
    }

    let mut y: [f32; 32] = [0_f32; 32];

    for i in 0..32 {
        y[i] = i as f32;
    }

    let z: [f32; 32] = x.cast();
    assert_eq!(z, y);
}

#[cfg(feature = "nightly")]
#[test]
fn test_i128_u128() {
    let x: i128 = 1;
    let y: u128 = x.cast();
    let z: f32 = y.cast();
    assert_eq!(x, 1_i128);
    assert_eq!(y, 1_u128);
    assert_eq!(z, 1_f32);
}