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
use core::{ mem::MaybeUninit, ops::{ RangeBounds, Bound, }, }; use crate::guards::SliceMemoryGuard; /// Guard-struct used to own uninitialized memory and provide functions for initializing it. /// Usually, you *should not* use this struct to handle your memory. /// /// Initializing functions spawns [SliceMemoryGuard] which will provide access to initialized memory. /// It also means memory can be used again after [SliceMemoryGuard] is dropped. /// /// ### Safety /// /// If you use this struct manually, remember: `&mut [MaybeUninit<T>]`'s content will be overwriten while initialization. /// So it is *not safe* to apply this struct to already initialized data and it can lead to *memory leaks*. /// /// ### Example /// ```rust /// use inplace_it::UninitializedSliceMemoryGuard; /// use std::mem::MaybeUninit; /// /// // Placing uninitialized memory /// let mut memory: [MaybeUninit<usize>; 100] = unsafe { MaybeUninit::uninit().assume_init() }; /// // Initializing guard /// let mut uninit_memory_guard = unsafe { UninitializedSliceMemoryGuard::new(&mut memory) }; /// /// { /// // Initializing memory /// let mut memory_guard = uninit_memory_guard /// // we need to call .borrow() because out init-API consumes uninit-guard /// .borrow() /// // then passing initialize closure and the guard is ok /// .init(|index| index * 2); /// // For now, memory contains content like [0, 2, 4, 6, ..., 196, 198] /// /// // Using memory /// // Sum of [0, 2, 4, 6, ..., 196, 198] = sum of [0, 1, 2, 3, ..., 98, 99] * 2 = ( 99 * (99+1) ) / 2 * 2 /// let sum: usize = memory_guard.iter().sum(); /// assert_eq!(sum, 99 * 100); /// // memory_guard dropped here /// } /// /// // uninit_memory_guard is available again now /// /// { /// // Initializing memory /// let mut memory_guard = uninit_memory_guard.init(|index| index * index); /// // For now, memory contains content like [0, 1, 4, 9, ..., 9604, 9801] /// /// // Using memory /// // Sum of [0, 1, 4, 9, ..., 9604, 9801] = 99 * (99 + 1) * (2 * 99 + 1) / 6 /// let sum: usize = memory_guard.iter().sum(); /// assert_eq!(sum, 99 * (99 + 1) * (2 * 99 + 1) / 6); /// // memory_guard dropped here /// } /// /// ``` /// /// [SliceMemoryGuard]: struct.SliceMemoryGuard.html pub struct UninitializedSliceMemoryGuard<'a, T> { memory: &'a mut [MaybeUninit<T>], } impl<'a, T> UninitializedSliceMemoryGuard<'a, T> { /// Initialize memory guard #[inline] pub unsafe fn new(memory: &'a mut [MaybeUninit<T>]) -> Self { Self { memory } } /// Get the length of memory slice #[inline] pub fn len(&self) -> usize { self.memory.len() } /// Construct new memory guard with new bounds. /// /// Can be used to shrink memory. /// /// ### Panics /// /// Panic can be reached when given `range` is out of memory's range. #[inline] pub fn slice(self, range: impl RangeBounds<usize>) -> Self { let start = match range.start_bound() { Bound::Excluded(n) => n.saturating_add(1), Bound::Included(n) => *n, Bound::Unbounded => 0, }; let end = match range.end_bound() { Bound::Excluded(n) => *n, Bound::Included(n) => n.saturating_add(1), Bound::Unbounded => self.memory.len(), }; Self { memory: &mut self.memory[start..end], } } /// Initialize memory and make new guard of initialized memory. /// Given `init` closure will be used to initialize elements of memory slice. #[inline] pub fn init(self, init: impl FnMut(usize) -> T) -> SliceMemoryGuard<'a, T> { unsafe { SliceMemoryGuard::new(self.memory, init) } } /// Initialize memory and make new guard of initialized memory. /// Given `source` slice will be used to initialize elements of memory slice. /// Returned guard will contain sliced memory to `source`'s length. /// /// ### Panics /// /// Panic can be reached when given `source`'s range is out of memory's range. #[inline] pub fn init_copy_of(self, source: &[T]) -> SliceMemoryGuard<'a, T> where T: Clone { self.slice(..source.len()).init(|index| { source[index].clone() }) } /// Initialize memory and make new guard of initialized memory. /// Given `iter` exact-size iterator will be used to initialize elements of memory slice. /// Returned guard will contain sliced memory to `iter`'s length. /// /// ### Panics /// /// Panic can be reached when given `iter`'s length is out of memory's range. #[inline] pub fn init_with_iter(self, mut iter: impl ExactSizeIterator<Item = T>) -> SliceMemoryGuard<'a, T> { self.slice(..iter.len()).init(|_index| { iter.next().unwrap() }) } /// Create new uninit memory guard with less or equal lifetime to original guard's lifetime. /// This function should be used to reuse memory because init-API consumes the guard. #[inline] pub fn borrow(&mut self) -> UninitializedSliceMemoryGuard<T> { unsafe { UninitializedSliceMemoryGuard::new(self.memory) } } }