#![no_std]
pub trait InitWith<T> {
fn init_with<F>(init: F) -> Self
where
F: FnMut() -> T,
Self: Sized;
fn init_with_indices<F>(init: F) -> Self
where
F: FnMut(usize) -> T,
Self: Sized;
}
macro_rules! array_init {
{$n:expr, $init:ident, $($stack:ident,)+} => {
impl<T> InitWith<T> for [T; $n] {
fn init_with<F>(mut $init: F) -> Self
where F: FnMut() -> T,
Self: Sized
{
[$init(), $($stack()),+]
}
fn init_with_indices<F>(mut $init: F) -> Self
where F: FnMut(usize) -> T
{
build_incrementing_list!([], 0, $init, $($stack),+)
}
}
array_init!{($n - 1), $($stack,)+}
};
{$n:expr, $init:ident,} => {
impl<T> InitWith<T> for [T; $n] {
fn init_with<F>(mut $init: F) -> Self
where F: FnMut() -> T,
Self: Sized
{
[$init()]
}
fn init_with_indices<F>(mut $init: F) -> Self
where F: FnMut(usize) -> T,
Self: Sized
{
[$init(0)]
}
}
array_init!{($n - 1)}
};
{$n:expr} => {
impl<T> InitWith<T> for [T; $n] {
fn init_with<F>(_init: F) -> Self
where F: FnMut() -> T,
Self: Sized
{
[]
}
fn init_with_indices<F>(_: F) -> Self
where F: FnMut(usize) -> T,
Self: Sized
{
[]
}
}
};
}
macro_rules! build_incrementing_list {
{[$($result:tt)*], $n:expr, $head:ident} => {
[$($result)* $head($n),]
};
{[$($result:tt)*], $n:expr, $head:ident, $($stack:ident),+} => {
build_incrementing_list!([$($result)* $head($n),], $n+1, $($stack),+)
};
}
array_init!{32, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init, init,}
#[cfg(test)]
mod tests {
use super::InitWith;
#[test]
fn expected() {
let val = <[i32; 3]>::init_with(|| 4);
assert_eq!(val, [4, 4, 4]);
}
#[test]
fn expected_build_incrementing_list() {
let val = <[usize; 5]>::init_with_indices(|x| x);
assert_eq!(val, [0, 1, 2, 3, 4]);
}
}