polkavm_common/
cast.rs

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
//! This module defines an explicit casting facility to replace Rust's built-in `as` casts.
//! The general idea is:
//!   * Casts should be usable everywhere, including in `const fn`s (which means we can't use traits).
//!   * Casts should fail to compile if a) the source or the target type changes, and b) the cast between the new pair of types would now be incorrect.
//!   * `usize` is assumed to be always at least 32-bit.

#[allow(non_camel_case_types)]
#[repr(transparent)]
pub struct cast<T>(pub T);

impl cast<i8> {
    #[inline(always)]
    pub const fn to_unsigned(self) -> u8 {
        self.0 as u8
    }

    #[inline(always)]
    pub const fn to_i32_sign_extend(self) -> i32 {
        self.0 as i32
    }

    #[inline(always)]
    pub const fn to_i64_sign_extend(self) -> i64 {
        self.0 as i64
    }
}

impl cast<i16> {
    #[inline(always)]
    pub const fn to_unsigned(self) -> u16 {
        self.0 as u16
    }

    #[inline(always)]
    pub const fn to_i32_sign_extend(self) -> i32 {
        self.0 as i32
    }

    #[inline(always)]
    pub const fn to_i64_sign_extend(self) -> i64 {
        self.0 as i64
    }
}

impl cast<i32> {
    #[inline(always)]
    pub const fn to_unsigned(self) -> u32 {
        self.0 as u32
    }

    #[inline(always)]
    pub const fn to_i64_sign_extend(self) -> i64 {
        self.0 as i64
    }
}

impl cast<i64> {
    #[inline(always)]
    pub const fn to_unsigned(self) -> u64 {
        self.0 as u64
    }
}

impl cast<u8> {
    #[inline(always)]
    pub const fn to_signed(self) -> i8 {
        self.0 as i8
    }

    #[inline(always)]
    pub const fn to_u64(self) -> u64 {
        self.0 as u64
    }
}

impl cast<u16> {
    #[inline(always)]
    pub const fn to_u64(self) -> u64 {
        self.0 as u64
    }
}

impl cast<u16> {
    #[inline(always)]
    pub const fn to_signed(self) -> i16 {
        self.0 as i16
    }

    #[inline(always)]
    pub const fn to_u32(self) -> u32 {
        self.0 as u32
    }
}

impl cast<u32> {
    #[inline(always)]
    pub const fn to_signed(self) -> i32 {
        self.0 as i32
    }

    #[inline(always)]
    pub const fn to_u64(self) -> u64 {
        self.0 as u64
    }

    #[inline(always)]
    pub const fn to_usize(self) -> usize {
        self.0 as usize
    }

    #[inline(always)]
    pub const fn truncate_to_u8(self) -> u8 {
        self.0 as u8
    }

    #[inline(always)]
    pub const fn truncate_to_u16(self) -> u16 {
        self.0 as u16
    }
}

impl cast<u64> {
    #[inline(always)]
    pub const fn assert_always_fits_in_u32(self) -> u32 {
        debug_assert!(self.0 <= u32::MAX as u64);
        self.0 as u32
    }

    #[inline(always)]
    pub const fn to_signed(self) -> i64 {
        self.0 as i64
    }

    #[inline(always)]
    pub const fn truncate_to_u8(self) -> u8 {
        self.0 as u8
    }

    #[inline(always)]
    pub const fn truncate_to_u16(self) -> u16 {
        self.0 as u16
    }

    #[inline(always)]
    pub const fn truncate_to_u32(self) -> u32 {
        self.0 as u32
    }
}

impl cast<usize> {
    #[inline(always)]
    pub const fn assert_always_fits_in_u32(self) -> u32 {
        debug_assert!(self.0 <= u32::MAX as usize);
        self.0 as u32
    }

    #[inline(always)]
    pub const fn to_u64(self) -> u64 {
        self.0 as u64
    }
}