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