#![cfg_attr(feature = "std", doc = r##"
This also works for types which need some additional information to initialise, such as a
run-time length:
```rust
use init_trait::Init;
struct House { number: usize }
// Vec<T>: Init<T, usize, usize>
let road = Vec::<House>::init_with(3, |i| House { number: i + 1 });
assert_eq!(road[0].number, 1);
assert_eq!(road[1].number, 2);
assert_eq!(road[2].number, 3);
```
"##)]
#![no_std]
#![feature(const_generics)]
#![doc(html_root_url = "https://docs.rs/init_trait/0.2.0")]
mod type_equals;
use type_equals::TypeEquals;
use core::marker::Sized;
use core::mem::{MaybeUninit, transmute_copy, forget};
#[cfg(feature = "std")]
extern crate std;
#[cfg(feature = "std")]
use std::vec::Vec;
#[cfg(all(not(feature = "std"), feature = "alloc"))]
extern crate alloc;
#[cfg(all(not(feature = "std"), feature = "alloc"))]
use alloc::vec::Vec;
pub trait Init<T, I, V = ()>: Sized {
#[cfg_attr(feature = "std", doc = r##"
Constructing a Vec containing the values 0 to 4:
```rust
use init_trait::Init;
let vec = Vec::<usize>::init_with(5, |i| i);
assert_eq!(vec, vec![0, 1, 2, 3, 4]);
```
"##)]
fn init_with<F: FnMut(I) -> T>(value: V, elem: F) -> Self;
fn init<F: FnMut(I) -> T>(elem: F) -> Self where V: TypeEquals<()> {
Self::init_with(().into(), elem)
}
}
impl<T, const N: usize> Init<T, usize> for [T; N] {
fn init_with<F: FnMut(usize) -> T>(_: (), mut elem: F) -> Self {
let mut contents: [MaybeUninit<T>; N] = unsafe { MaybeUninit::uninit().assume_init() };
for i in 0..N {
contents[i] = MaybeUninit::new(elem(i));
}
let res = unsafe { transmute_copy(&contents) };
forget(contents);
res
}
}
impl<T, const N1: usize, const N2: usize> Init<T, [usize; 2]> for [[T; N1]; N2] {
fn init_with<F: FnMut([usize; 2]) -> T>(_: (), mut elem: F) -> Self {
Self::init(|i1| <[T; N1]>::init(|i2| elem([i1, i2])))
}
}
impl<T, const N1: usize, const N2: usize, const N3: usize> Init<T, [usize; 3]> for [[[T; N1]; N2]; N3] {
fn init_with<F: FnMut([usize; 3]) -> T>(_: (), mut elem: F) -> Self {
Self::init(|i1| <[[T; N1]; N2]>::init(|[i2, i3]: [usize; 2]| elem([i1, i2, i3])))
}
}
impl<T, const N1: usize, const N2: usize, const N3: usize, const N4: usize> Init<T, [usize; 4]> for [[[[T; N1]; N2]; N3]; N4] {
fn init_with<F: FnMut([usize; 4]) -> T>(_: (), mut elem: F) -> Self {
Self::init(|i1| <[[[T; N1]; N2]; N3]>::init(|[i2, i3, i4]: [usize; 3]| elem([i1, i2, i3, i4])))
}
}
impl<T, const N1: usize, const N2: usize, const N3: usize, const N4: usize, const N5: usize> Init<T, [usize; 5]> for [[[[[T; N1]; N2]; N3]; N4]; N5] {
fn init_with<F: FnMut([usize; 5]) -> T>(_: (), mut elem: F) -> Self {
Self::init(|i1| <[[[[T; N1]; N2]; N3]; N4]>::init(|[i2, i3, i4, i5]: [usize; 4]| elem([i1, i2, i3, i4, i5])))
}
}
impl<T, const N1: usize, const N2: usize, const N3: usize, const N4: usize, const N5: usize, const N6: usize> Init<T, [usize; 6]> for [[[[[[T; N1]; N2]; N3]; N4]; N5]; N6] {
fn init_with<F: FnMut([usize; 6]) -> T>(_: (), mut elem: F) -> Self {
Self::init(|i1| <[[[[[T; N1]; N2]; N3]; N4]; N5]>::init(|[i2, i3, i4, i5, i6]: [usize; 5]| elem([i1, i2, i3, i4, i5, i6])))
}
}
#[cfg(any(feature = "std", feature = "alloc"))]
impl<T> Init<T, usize, usize> for Vec<T> {
fn init_with<F: FnMut(usize) -> T>(length: usize, mut elem: F) -> Self {
let mut value = Vec::with_capacity(length);
for i in 0..length {
value.push(elem(i));
}
value
}
}