core_extensions/utils.rs
1//! Miscelaneous utility functions
2
3#[cfg(feature = "alloc")]
4use alloc::vec::Vec;
5
6use std_::mem::{self, ManuallyDrop};
7
8/// Allows transmuting between types of different sizes.
9///
10/// Necessary for transmuting in generic functions, since (as of Rust 1.51.0)
11/// transmute doesn't work well with generic types.
12///
13/// # Safety
14///
15/// This function has the same safety requirements as [`std::mem::transmute_copy`].
16///
17/// # Example
18///
19/// ```rust
20/// use core_extensions::utils::transmute_ignore_size;
21///
22/// use std::mem::MaybeUninit;
23///
24/// unsafe fn transmute_into_init<T>(array: [MaybeUninit<T>; 3]) -> [T; 3] {
25/// transmute_ignore_size(array)
26/// }
27///
28/// let array = [MaybeUninit::new(3), MaybeUninit::new(5), MaybeUninit::new(8)];
29///
30/// unsafe{ assert_eq!(transmute_into_init(array), [3, 5, 8]); }
31///
32/// ```
33///
34/// This is the error you get if you tried to use `std::mem::transmute`.
35///
36/// ```text
37/// error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
38/// --> src/lib.rs:4:5
39/// |
40/// 4 | std::mem::transmute(array)
41/// | ^^^^^^^^^^^^^^^^^^^
42/// |
43/// = note: source type: `[MaybeUninit<T>; 3]` (size can vary because of T)
44/// = note: target type: `[T; 3]` (size can vary because of T)
45/// ```
46///
47///
48/// [`std::mem::transmute_copy`]: https://doc.rust-lang.org/std/mem/fn.transmute_copy.html
49#[inline(always)]
50pub unsafe fn transmute_ignore_size<T, U>(v: T) -> U {
51 let v=ManuallyDrop::new(v);
52 mem::transmute_copy::<T, U>(&v)
53}
54
55/// Transmutes a `Vec<T>` into a `Vec<U>`
56///
57/// # Safety
58///
59/// This function has the safety requirements of [`std::mem::transmute`]
60/// regarding transmuting from `T` to `U`.
61/// `T` must also have the same alignment as `U`.
62///
63/// # Example
64///
65/// ```rust
66/// use core_extensions::utils::transmute_vec;
67///
68/// use std::mem::ManuallyDrop;
69///
70/// unsafe{
71/// assert_eq!(transmute_vec::<u32, i32>(vec![!0, 0, 1]), vec![-1, 0, 1]);
72/// }
73///
74/// fn make(s: &str) -> ManuallyDrop<String> {
75/// ManuallyDrop::new(String::from(s))
76/// }
77/// unsafe{
78/// assert_eq!(
79/// transmute_vec::<String, ManuallyDrop<String>>(vec!["hello".into(), "world".into()]),
80/// vec![make("hello"), make("world")],
81/// );
82/// }
83///
84/// ```
85///
86/// [`std::mem::transmute`]: https://doc.rust-lang.org/std/mem/fn.transmute.html
87#[cfg(feature = "alloc")]
88#[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))]
89pub unsafe fn transmute_vec<T, U>(vector: Vec<T>) -> Vec<U> {
90 let len = vector.len();
91 let capacity = vector.capacity();
92 let mut vector = ManuallyDrop::new(vector);
93 Vec::from_raw_parts(vector.as_mut_ptr() as *mut U, len, capacity)
94}
95
96
97
98/// Use this function to mark to the compiler that this branch is impossible.
99///
100/// This function panics when debug assertions are enabled,
101/// if debug assertions are disabled then reaching this is undefined behaviour.
102///
103/// For a version which doesn't panic in debug builds but instead always causes
104/// undefined behaviour when reached you can use
105/// [`std::hint::unreachable_unchecked`].
106///
107/// # Safety
108///
109/// It is undefined behaviour for this function to be reached at runtime at all.
110///
111/// The compiler is free to delete any code that reaches and depends on this function,
112/// on the assumption that this branch can't be reached.
113///
114/// # Example
115#[cfg_attr(feature = "bools", doc = " ```rust")]
116#[cfg_attr(not(feature = "bools"), doc = " ```ignore")]
117/// use core_extensions::BoolExt;
118/// use core_extensions::utils::impossible;
119///
120/// mod non_zero{
121/// use super::*;
122/// #[derive(Debug,Copy,Clone)]
123/// pub struct NonZero(usize);
124///
125/// impl NonZero{
126/// pub fn new(value:usize) -> Option<NonZero> {
127/// (value!=0).if_true(|| NonZero(value))
128/// }
129/// pub fn value(&self)->usize{
130/// self.0
131/// }
132/// }
133/// }
134/// use self::non_zero::NonZero;
135///
136/// # fn main(){
137///
138/// fn div(numerator: usize, denom: Option<NonZero>) -> usize{
139/// let denom = match denom {
140/// Some(v) if v.value() == 0 => unsafe{
141/// // unreachable: NonZero::value() can never be 0,
142/// impossible()
143/// },
144/// Some(v) => v.value(),
145/// None => 1,
146/// };
147/// numerator / denom
148/// }
149///
150/// assert_eq!(div(60, NonZero::new(0)), 60);
151/// assert_eq!(div(60, NonZero::new(1)), 60);
152/// assert_eq!(div(60, NonZero::new(2)), 30);
153/// assert_eq!(div(60, NonZero::new(3)), 20);
154/// assert_eq!(div(60, NonZero::new(4)), 15);
155/// assert_eq!(div(60, NonZero::new(5)), 12);
156/// assert_eq!(div(60, NonZero::new(6)), 10);
157///
158///
159/// # }
160///
161///
162///
163/// ```
164///
165/// [`std::hint::unreachable_unchecked`]:
166/// https://doc.rust-lang.org/std/hint/fn.unreachable_unchecked.html
167///
168///
169#[inline(always)]
170pub unsafe fn impossible() -> ! {
171 #[cfg(debug_assertions)]
172 {
173 panic!("reached core_extensions::impossible() ")
174 }
175 #[cfg(not(debug_assertions))]
176 {
177 std_::hint::unreachable_unchecked()
178 }
179}
180
181
182////////////////////////////////////////////////////////////////////////////////
183
184
185/// Takes the contents out of a `ManuallyDrop<T>`.
186///
187/// # Safety
188///
189/// After this function is called `slot` becomes uninitialized,
190/// and must not be used again.
191#[allow(dead_code)]
192pub(crate) unsafe fn take_manuallydrop<T>(slot: &mut ManuallyDrop<T>) -> T {
193 #[cfg(feature = "rust_1_42")]
194 {
195 ManuallyDrop::take(slot)
196 }
197 #[cfg(not(feature = "rust_1_42"))]
198 {
199 ::std_::ptr::read(slot as *mut ManuallyDrop<T> as *mut T)
200 }
201}
202
203
204////////////////////////////////////////////////////////////////////////////////
205
206
207#[cfg(test)]
208mod tests{
209 use super::*;
210
211 use std_::cell::Cell;
212 use test_utils::DecOnDrop;
213
214 #[test]
215 fn take_manuallydrop_test(){
216 let count = Cell::new(10);
217 let mut md = ManuallyDrop::new(DecOnDrop::new(&count));
218
219 assert_eq!(count.get(), 10);
220
221 let dod = unsafe{ take_manuallydrop(&mut md) };
222 assert_eq!(count.get(), 10);
223
224 drop(dod);
225 assert_eq!(count.get(), 9);
226 }
227}
228