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)
        }
    }
}