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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
//! An [`ArrayInitializer<T>`] is an object that knows how to initialize the memory for a `[T]`.
//! It is useful for initializing `[T; N]` or (of more relevance for this crate) initializing
//! a `varlen::array::Array<T>`.
//!
//! # Examples
//!
//! Initializing a `[T; N]` from an initializer:
//!
//! ```
//! use varlen::prelude::*;
//!
//! let arr: [u16; 4] = new_array(FillWithDefault);
//! assert_eq!([0, 0, 0, 0], arr);
//!
//! let arr2: [u16; 4] = new_array(FillSequentially(|i| (i * 2) as u16));
//! assert_eq!([0, 2, 4, 6], arr2);
//! ```
//!
//! Initializing a `varlen::array::Array<T>` from an initializer:
//!
//! ```
//! use varlen::prelude::*;
//!
//! let arr: VBox<Array<u16>> = VBox::new(SizedInit(4, FillSequentially(|i| (i * 2) as u16)));
//! assert_eq!(&[0, 2, 4, 6], &arr[..]);
//! ```

use core::mem::MaybeUninit;

trait HasUninit: Sized {
    const UNINIT: MaybeUninit<Self>;
}

impl<T> HasUninit for T {
    const UNINIT: MaybeUninit<Self> = MaybeUninit::uninit();
}

/// Initializes an array from an initializer.
///
/// # Examples
///
/// ```
/// use varlen::prelude::*;
///
/// let arr: [u16; 4] = new_array(FillSequentially(|i| (i * 2) as u16));
/// assert_eq!([0, 2, 4, 6], arr);
/// ```
pub fn new_array<T, const N: usize>(init: impl ArrayInitializer<T>) -> [T; N] {
    let mut data = [HasUninit::UNINIT; N];
    init.initialize(&mut data);
    unsafe {
        // Safety:
        // * guaranteed to be initialized by safety requirement on ArrayInitializer
        // * size and alignment are guaranteed to match between [MaybeUninit<T>; N]
        //   and [T; N]
        transmute_workaround(data)
    }
}

/// An object that is able to initialize an array of `T` values.
///
/// # Examples
///
/// An initializer that fills an array from end to start:
///
/// ```
/// use varlen::prelude::*;
/// use std::mem::MaybeUninit;
///
/// struct WriteBackwardsPowersOf3;
/// unsafe impl ArrayInitializer<u64> for WriteBackwardsPowersOf3 {
///     fn initialize(self, dst: &mut [MaybeUninit<u64>]) {
///         let mut v = 1;
///         for slot in dst.iter_mut().rev() {
///             slot.write(v);
///             v *= 3;
///         }
///     }
/// }
///
/// assert_eq!([81, 27, 9, 3, 1], varlen::array_init::new_array(WriteBackwardsPowersOf3));
/// ```
pub unsafe trait ArrayInitializer<T> {
    /// Fills the slice.
    ///
    /// ```
    /// use std::mem::MaybeUninit;
    /// use varlen::prelude::*;
    /// const UNINIT_U16: MaybeUninit<u16> = MaybeUninit::uninit();
    /// let mut arr = [UNINIT_U16; 4];
    /// FillWithDefault.initialize(&mut arr[..]);
    /// for slot in arr {
    ///     assert_eq!(0, unsafe { slot.assume_init() });
    /// }
    /// ```
    fn initialize(self, dst: &mut [MaybeUninit<T>]);
}

/// Fills an array from a prefix of an iterator.
///
/// # Example
///
/// ```
/// use varlen::prelude::*;
/// let iter = std::iter::successors(Some(3), |i| Some(i * 3));
/// let arr: [u16; 5] = new_array(FromIterPrefix(iter));
/// assert_eq!(arr, [3, 9, 27, 81, 243]);
/// ```
///
/// # Panics
///
/// Panics if the iterator yields fewer elements than the desired output size.
///
/// ```should_panic
/// use varlen::prelude::*;
/// let iter = std::iter::successors(Some(3), |i| Some(i * 3));
/// let arr: [u16; 5] = new_array(FromIterPrefix(iter.take(3))); // Panics
/// ```
pub struct FromIterPrefix<Iter>(pub Iter);

unsafe impl<T, Iter: Iterator<Item = T>> ArrayInitializer<T> for FromIterPrefix<Iter> {
    fn initialize(mut self, dst: &mut [MaybeUninit<T>]) {
        for slot in dst.iter_mut() {
            slot.write(
                self.0
                    .next()
                    .unwrap_or_else(|| panic!("Iterator had too few elements")),
            );
        }
    }
}

/// Fills an array by calling the function for every element, in ascending order by index.
///
/// The function is given the `usize` element index as a parameter.
///
/// # Examples
///
/// ```
/// use varlen::prelude::*;
/// let arr: [u16; 5] = new_array(FillSequentially(|i| (i as u16) * 2));
/// assert_eq!(arr, [0, 2, 4, 6, 8]);
/// ```
///
/// Stateful functions are also allowed:
///
/// ```
/// use varlen::prelude::*;
/// let mut state = 1;
/// let arr: [u16; 5] = new_array(FillSequentially(|_| {
///     state = state * 3;
///     state
/// }));
/// assert_eq!(arr, [3, 9, 27, 81, 243]);
/// ```
pub struct FillSequentially<Lambda>(pub Lambda);

unsafe impl<T, Lambda: FnMut(usize) -> T> ArrayInitializer<T> for FillSequentially<Lambda> {
    fn initialize(mut self, dst: &mut [MaybeUninit<T>]) {
        for (i, slot) in dst.iter_mut().enumerate() {
            slot.write(self.0(i));
        }
    }
}

/// Fills an array with [`Default::default()`].
///
/// # Examples
///
/// ```
/// use varlen::prelude::*;
/// let arr: [u16; 5] = new_array(FillWithDefault);
/// assert_eq!(arr, [0, 0, 0, 0, 0]);
/// ```
pub struct FillWithDefault;

unsafe impl<T: Default> ArrayInitializer<T> for FillWithDefault {
    fn initialize(self, dst: &mut [MaybeUninit<T>]) {
        FillSequentially(|_i| Default::default()).initialize(dst)
    }
}

/// Fills an array by copying from a source array. Source and destination must have identical length.
///
/// # Examples
///
/// ```
/// use varlen::prelude::*;
/// let arr: [u16; 5] = new_array(CopyFrom(&[3, 1, 4, 1, 5]));
/// assert_eq!(arr, [3, 1, 4, 1, 5]);
/// ```
///
/// # Panics
///
/// Panics if the source and destination arrays have different length.
///
/// ```should_panic
/// use varlen::prelude::*;
/// let arr: [u16; 6] = new_array(CopyFrom(&[3, 1, 4, 1, 5]));  // Panic
/// ```
///
/// ```should_panic
/// use varlen::prelude::*;
/// let arr: [u16; 4] = new_array(CopyFrom(&[3, 1, 4, 1, 5]));  // Panic
/// ```
pub struct CopyFrom<'a, T>(pub &'a [T]);

unsafe impl<'a, T: Copy> ArrayInitializer<T> for CopyFrom<'a, T> {
    fn initialize(self, dst: &mut [MaybeUninit<T>]) {
        // TODO(reinerp): Use MaybeUninit::write_slice once it stabilizes.
        // Safety: MaybeUninit<T> and T have the same layout.
        let src: &[MaybeUninit<T>] = unsafe { core::mem::transmute(self.0) };
        dst.copy_from_slice(src)
    }
}

/// Fills an array by cloning from a source array. Source and destination must have identical length.
///
/// # Examples
///
/// ```
/// use varlen::prelude::*;
///
/// let src = ["hello".to_string(), "world".to_string()];
/// let arr: [String; 2] = new_array(CloneFrom(&src));
/// assert_eq!(src, arr);
/// ```
///
/// # Panics
///
/// Panics if the source and destination have different lengths.
///
/// ```should_panic
/// # use varlen::prelude::*;
/// #
/// # let src = ["hello".to_string(), "world".to_string()];
/// let arr: [String; 1] = new_array(CloneFrom(&src));  // Panics
/// ```
pub struct CloneFrom<'a, T>(pub &'a [T]);

unsafe impl<'a, T: Clone> ArrayInitializer<T> for CloneFrom<'a, T> {
    fn initialize(self, dst: &mut [MaybeUninit<T>]) {
        assert_eq!(self.0.len(), dst.len());
        for (src, dst) in self.0.iter().zip(dst.iter_mut()) {
            dst.write(src.clone());
        }
    }
}

/// Fills an array by moving from a source array. Source and destination must have identical length.
///
/// # Examples
///
/// ```
/// use varlen::prelude::*;
///
/// let src = ["hello".to_string(), "world".to_string()];
/// let arr: [String; 2] = new_array(MoveFrom(src));
/// assert_eq!(arr, ["hello".to_string(), "world".to_string()]);
/// ```
///
/// # Panics
///
/// Panics if the source and destination have different lengths.
///
/// ```should_panic
/// # use varlen::prelude::*;
/// #
/// # let src = ["hello".to_string(), "world".to_string()];
/// let arr: [String; 1] = new_array(MoveFrom(src));  // Panics
/// ```
pub struct MoveFrom<T, const N: usize>(pub [T; N]);

unsafe impl<T, const N: usize> ArrayInitializer<T> for MoveFrom<T, N> {
    fn initialize(self, dst: &mut [MaybeUninit<T>]) {
        assert_eq!(dst.len(), N);
        for (src, dst) in self.0.into_iter().zip(dst.iter_mut()) {
            dst.write(src);
        }
    }
}

/// Same as `transmute`, but supports types whose sizes are not known until monomorphization.
unsafe fn transmute_workaround<T, U>(e: T) -> U {
    assert!(core::alloc::Layout::new::<T>() == core::alloc::Layout::new::<U>());
    let u = core::mem::transmute_copy(&e);
    core::mem::forget(e);
    u
}