array-fusion 0.2.0

Array merging and splitting facilities
Documentation
//! Array of arrays utilities.


use core::ops::Mul;

pub use hybrid_array;
use hybrid_array::Array;
use hybrid_array::ArraySize;
use hybrid_array::AssocArraySize;
use hybrid_array::typenum::Prod;

#[cfg(doc)]
use crate::array_from_core;
#[cfg(doc)]
use crate::array_to_core;



/// Flatten an array of arrays into a single contigues array.
///
/// # Examples
///
/// ```rust
/// use array_fusion::hybrid_array::Array;
/// use array_fusion::hybrid_array::sizes::{U2, U3, U6};
/// use array_fusion::chunks::flatten;
///
/// let array_of_arrays: Array<Array<u8, U2>, U3> = Array([
///     Array([1, 2]),
///     Array([3, 4]),
///     Array([5, 6]),
/// ]);
///
/// let flattened: Array<u8, U6> = flatten(array_of_arrays);
///
/// assert_eq!(flattened, Array([1, 2, 3, 4, 5, 6]));
/// ```
pub fn flatten<T, I, O>(input: Array<Array<T, I>, O>) -> Array<T, Prod<I, O>>
where
	I: Mul<O>,
	I::Output: ArraySize,
	I: ArraySize,
	O: ArraySize,
	// TODO: find a way to lift this constraint
	T: Default + Copy,
{
	let mut output = Array::default();

	// TODO: is there a more efficient way to do this?

	let mut offset = 0;
	for array in input.iter() {
		let len = array.len();
		output[offset..offset + len].copy_from_slice(array);
		offset += len;
	}

	output
}

/// Split a contigues array into an array of arrays.
///
///
/// # Examples
///
/// ```rust
/// use array_fusion::hybrid_array::Array;
/// use array_fusion::hybrid_array::sizes::{U2, U3, U6};
/// use array_fusion::chunks::chunks;
///
/// let input: Array<u8, U6> = Array([1, 2, 3, 4, 5, 6]);
///
/// let chunked: Array<Array<u8, U2>, U3> = chunks(input);
///
/// assert_eq!(chunked, Array([
///     Array([1, 2]),
///     Array([3, 4]),
///     Array([5, 6]),
/// ]));
/// ```
pub fn chunks<T, I, O>(input: Array<T, Prod<I, O>>) -> Array<Array<T, I>, O>
where
	I: Mul<O>,
	I::Output: ArraySize,
	I: ArraySize,
	O: ArraySize,
	// TODO: find a way to lift this constraint
	T: Default + Copy,
{
	let mut output: Array<Array<T, I>, O> = Array::default();

	let mut offset = 0;
	for array in output.iter_mut() {
		let len = array.len();
		array.copy_from_slice(&input[offset..offset + len]);
		offset += len;
	}

	output
}

/// Type alias for an `Array` of `Array`s using const generic sizes.
///
/// This is just a shorthand for `Array<Array<T, IT>, OT>`, where `IT` and `OT`
/// are the respective `typenum` sizes for `I` and `O`.
///
/// This is mostly useful when working with const generics, to avoid having
/// to manually map from const generics to `typenum` sizes.
///
/// # Example
///
/// ```rust
/// use array_fusion::chunks::ArrayOfArrays;
/// use array_fusion::hybrid_array::Array;
/// use array_fusion::hybrid_array::sizes::{U2, U3};
///
/// let array_of_arrays: ArrayOfArrays<u8, 3, 2> =
/// # Array([
/// #    Array([10, 20, 30]),
/// #    Array([40, 50, 60]),
/// # ])
///     /* -snip- */ ;
/// // => equals the following type:
/// let array_of_arrays: Array<Array<u8, U3>, U2> = array_of_arrays;
/// ```
pub type ArrayOfArrays<T, const I: usize, const O: usize> =
	Array<Array<T, <[T; I] as AssocArraySize>::Size>, <[[T; I]; O] as AssocArraySize>::Size>;

/// Converts an `Array` of `Array`s into a core array of arrays.
///
/// Notice this is similar to the [`array_to_core`] function, but works on
/// chunks (i.e. arrays of arrays).
pub fn chunks_to_core<T, const I: usize, const O: usize>(
	input: ArrayOfArrays<T, I, O>,
) -> [[T; I]; O]
where
	[T; I]: AssocArraySize,
	[[T; I]; O]: AssocArraySize,
	<[T; I] as AssocArraySize>::Size: ArraySize<ArrayType<T> = [T; I]>,
	<[[T; I]; O] as AssocArraySize>::Size: ArraySize<ArrayType<[T; I]> = [[T; I]; O]>,
{
	let a = input.map(|array| array.0);

	a.0
}

/// Converts a core array of arrays into an `Array` of `Array`s.
///
/// This is similar to the [`array_from_core`] function, but works on
/// chunks (i.e. arrays of arrays).
pub fn chunks_from_core<T, const I: usize, const O: usize>(
	input: [[T; I]; O],
) -> ArrayOfArrays<T, I, O>
where
	[T; I]: AssocArraySize,
	[[T; I]; O]: AssocArraySize,
	<[T; I] as AssocArraySize>::Size: ArraySize<ArrayType<T> = [T; I]>,
	<[[T; I]; O] as AssocArraySize>::Size: ArraySize<ArrayType<[T; I]> = [[T; I]; O]>,
{
	Array(input).map(|array| Array(array))
}