@@ -148,3 +148,76 @@ impl_disjoint_bitor! {
148
148
u8 , u16 , u32 , u64 , u128 , usize ,
149
149
i8 , i16 , i32 , i64 , i128 , isize ,
150
150
}
151
+
152
+ #[ const_trait]
153
+ #[ rustc_const_unstable( feature = "core_intrinsics_fallbacks" , issue = "none" ) ]
154
+ pub trait FunnelShift : Copy + ' static {
155
+ /// See [`super::unchecked_funnel_shl`]; we just need the trait indirection to handle
156
+ /// different types since calling intrinsics with generics doesn't work.
157
+ unsafe fn unchecked_funnel_shl ( self , rhs : Self , shift : u32 ) -> Self ;
158
+
159
+ /// See [`super::unchecked_funnel_shr`]; we just need the trait indirection to handle
160
+ /// different types since calling intrinsics with generics doesn't work.
161
+ unsafe fn unchecked_funnel_shr ( self , rhs : Self , shift : u32 ) -> Self ;
162
+ }
163
+
164
+ macro_rules! impl_funnel_shifts {
165
+ ( $( $type: ident) ,* ) => { $(
166
+ #[ rustc_const_unstable( feature = "core_intrinsics_fallbacks" , issue = "none" ) ]
167
+ impl const FunnelShift for $type {
168
+ #[ cfg_attr( miri, track_caller) ]
169
+ #[ inline]
170
+ unsafe fn unchecked_funnel_shl( self , rhs: Self , shift: u32 ) -> Self {
171
+ // This implementation is also used by Miri so we have to check the precondition.
172
+ // SAFETY: this is guaranteed by the caller
173
+ unsafe { super :: assume( shift < $type:: BITS ) } ;
174
+ if shift == 0 {
175
+ self
176
+ } else {
177
+ // SAFETY:
178
+ // - `shift < T::BITS`, which satisfies `unchecked_shl`
179
+ // - this also ensures that `T::BITS - shift < T::BITS` (shift = 0 is checked
180
+ // above), which satisfies `unchecked_shr`
181
+ // - because the types are unsigned, the combination are disjoint bits (this is
182
+ // not true if they're signed, since SHR will fill in the empty space with a
183
+ // sign bit, not zero)
184
+ unsafe {
185
+ super :: disjoint_bitor(
186
+ super :: unchecked_shl( self , shift) ,
187
+ super :: unchecked_shr( rhs, $type:: BITS - shift) ,
188
+ )
189
+ }
190
+ }
191
+ }
192
+
193
+ #[ cfg_attr( miri, track_caller) ]
194
+ #[ inline]
195
+ unsafe fn unchecked_funnel_shr( self , rhs: Self , shift: u32 ) -> Self {
196
+ // This implementation is also used by Miri so we have to check the precondition.
197
+ // SAFETY: this is guaranteed by the caller
198
+ unsafe { super :: assume( shift < $type:: BITS ) } ;
199
+ if shift == 0 {
200
+ rhs
201
+ } else {
202
+ // SAFETY:
203
+ // - `shift < T::BITS`, which satisfies `unchecked_shr`
204
+ // - this also ensures that `T::BITS - shift < T::BITS` (shift = 0 is checked
205
+ // above), which satisfies `unchecked_shl`
206
+ // - because the types are unsigned, the combination are disjoint bits (this is
207
+ // not true if they're signed, since SHR will fill in the empty space with a
208
+ // sign bit, not zero)
209
+ unsafe {
210
+ super :: disjoint_bitor(
211
+ super :: unchecked_shl( self , $type:: BITS - shift) ,
212
+ super :: unchecked_shr( rhs, shift) ,
213
+ )
214
+ }
215
+ }
216
+ }
217
+ }
218
+ ) * } ;
219
+ }
220
+
221
+ impl_funnel_shifts ! {
222
+ u8 , u16 , u32 , u64 , u128 , usize
223
+ }
0 commit comments