use std::{
alloc::{alloc_zeroed, Layout},
mem::transmute,
};
mod private {
use std::marker::PhantomData;
pub trait CUList {
type CoordType;
}
pub type CoordType<A> = <A as CUList>::CoordType;
pub struct Value {}
impl CUList for Value {
type CoordType = ();
}
pub struct Array<L: CUList, const N: usize> {
_l: PhantomData<L>,
}
impl<L: CUList, const N: usize> CUList for Array<L, N> {
type CoordType = (L::CoordType, usize);
}
pub trait Reify<T> {
fn reify() -> T;
}
impl Reify<usize> for Value {
fn reify() -> usize {
0
}
}
impl<L: CUList + Reify<usize>, const N: usize> Reify<usize> for Array<L, N> {
fn reify() -> usize {
1 + L::reify()
}
}
impl Reify<CoordType<Value>> for Value {
fn reify() -> CoordType<Value> {
()
}
}
impl<L: CUList + Reify<CoordType<L>>, const N: usize> Reify<CoordType<Array<L, N>>>
for Array<L, N>
{
fn reify() -> CoordType<Array<L, N>> {
(L::reify(), N)
}
}
pub trait Product<T> {
fn product() -> T;
}
impl Product<usize> for Value {
fn product() -> usize {
1
}
}
impl<L: CUList + Product<usize>, const N: usize> Product<usize> for Array<L, N> {
fn product() -> usize {
N * L::product()
}
}
pub trait IndexCoord<L: CUList> {
fn coords(i: usize) -> CoordType<L>;
}
impl IndexCoord<Value> for Value {
fn coords(_: usize) -> CoordType<Value> {
()
}
}
impl<L: CUList + IndexCoord<L> + Product<usize>, const N: usize> IndexCoord<Array<L, N>>
for Array<L, N>
{
fn coords(i: usize) -> CoordType<Array<L, N>> {
let prod = L::product();
(L::coords(i % prod), i / prod)
}
}
pub trait Arrays<E, L: CUList> {}
impl<E> Arrays<E, Value> for E {}
impl<E, L: CUList, A: Arrays<E, L>, const N: usize> Arrays<E, Array<L, N>> for [A; N] {}
}
use private::*;
pub use private::{Array, Value};
pub fn boxarray<E: Clone, L: CUList, A: Arrays<E, L>>(e: E) -> Box<A> {
unsafe {
let ptr = alloc_zeroed(Layout::new::<A>());
let se = std::mem::size_of::<E>();
if se != 0 {
let st = std::mem::size_of::<A>();
let n = st / se;
let arr: *mut E = transmute(ptr);
for i in 0..n {
*arr.add(i) = e.clone();
}
}
Box::from_raw(std::mem::transmute(ptr))
}
}
pub fn boxarray_<E, L: CUList + IndexCoord<L>, A: Arrays<E, L>, F: Fn(CoordType<L>) -> E>(
f: F,
) -> Box<A> {
unsafe {
let ptr = alloc_zeroed(Layout::new::<A>());
let se = std::mem::size_of::<E>();
if se != 0 {
let st = std::mem::size_of::<A>();
let n = st / se;
let arr: *mut E = transmute(ptr);
for i in 0..n {
*arr.add(i) = f(L::coords(i));
}
}
Box::from_raw(std::mem::transmute(ptr))
}
}