array-fusion 0.2.0

Array merging and splitting facilities
Documentation
//! A few utility macros.
//!
//! If you work with byte arrays, consider using the utilities from the
//! `crate::bytes` module instead.
//!

#[cfg(doc)]
use hybrid_array::Array;
#[cfg(doc)]
use hybrid_array::typenum;

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

/// Splits an [`Array`] into multiple sub-`Array`s.
///
/// Notice that each sub-`Array` must have a defined size, and the total
/// size of the sub-`Array`s must match the size of the `Aarray` on the
/// right-hand side.
///
/// The macro expects a let-assignment style syntax with a array pattern,
/// where each element happens to be bind a new variable with type `Array`.
///
/// If the size of a sub-`Array` cannot be inferred, you can specify it
/// explicitly by adding `: array <size>` after the variable name, where
/// `<size>` is a type of an `typenum` type-"number".
///
/// This macro is the reversal of the [`crate::merge_array`] macro.
///
/// # Syntax
///
/// ```text
/// split_array!{
///     let split \[
///         ( <name> [ : array <typenum-size> ] , )*
///     \] = <value>;
/// }
/// ```
///
/// # Example
///
/// ```
/// use hybrid_array::Array;
/// use array_fusion::array_from_core;
/// use array_fusion::array_to_core;
/// use array_fusion::split_array;
/// use hybrid_array::sizes::U4;
///
/// // An Array consisting of a 2-byte and a 4-byte sub array
/// let data: Array<_,_> = array_from_core([
///     0, 42, // foo
///     0x0, 0x0, 0x12, 0x34, // bar
/// ]);
///
/// // Split it into a `foo` and a `bar`.
/// // The size of foo is inferred by the subsequent usage, while bar is given
/// // an explicit size.
/// split_array!{
/// 	let split [
///         foo,
///         bar: array U4,
///     ] = data;
/// };
///
/// // Use foo in a way to make its size inferrable, where `from_be_bytes`
/// // gives the size of the core array, and `array_to_core` inferres the
/// // Array size from the size of that core array.
/// let foo = u16::from_be_bytes(array_to_core(foo));
/// assert_eq!(foo, 42);
///
/// // Use bar, actually this could also infer the size, but we specified it
/// // already above.
/// assert_eq!(u32::from_be_bytes(array_to_core(bar)), 0x1234);
/// ```
///
#[macro_export]
macro_rules! split_array {
	(
		let split [
			$($name:ident $( : array $size:ty)?  ),* $(,)?
		] = $data:expr $(;)?
	) => {

		// Ensure we got an array type
		let rest: $crate::Array<_, _> = $data;

		$(
		let (sub, rest) = rest.split $( ::<$size> )? () ;
		let $name = sub;
		)*

		// Assert that we split the entire array
		let _rest: $crate::Array<_, $crate::sizes::U0> = rest;
	};
}

/// Split a core arrays in core arrays.
///
/// This function is essentially [`split_array`], but on core arrays.
/// In fact, it is implemented using `split_array` and surrounds the right-hand
/// side with [`array_from_core`] and the output arrays with [`array_to_core`].
///
/// Also if you need to specify the size of an array you have to specifiy the
/// full core array.
///
///
/// # Syntax
///
/// ```text
/// split_core_array!{
///     let split \[
///         ( <name> [ : <array-type> ] , )*
///     \] = <value>;
/// }
/// ```
///
/// # Example
///
/// ```
/// use array_fusion::split_core_array;
///
/// let data = [
///     0, 42, // foo
///     0x0, 0x0, 0x12, 0x34, // bar
/// ];
///
/// // Split the array, core to core
/// // The size of `foo` is inferred from the subsequent usage of it, whereas
/// // the size of `bar` is explicitly specified.
/// split_core_array! {
///     let split [
///         foo,
///         bar: [_; 4],
///     ] = data;
/// };
///
/// // Use foo in a way to make it's size inferrable
/// let foo = u16::from_be_bytes(foo);
/// assert_eq!(foo, 42);
///
/// // Use bar, actually this would also infere its size, but we specified it
/// // already above.
/// assert_eq!(u32::from_be_bytes(bar), 0x1234);
/// ```
///
#[macro_export]
macro_rules! split_core_array {
	(
		let split [
			$($name:ident $( : $ty:ty)? ),* $(,)?
		] = $data:expr $(;)?
	) => {

		$crate::split_array!{
			let split [
				$($name),*
			] = $crate::array_from_core($data);
		}

		$(
			let $name $( : $ty )? = $crate::array_to_core($name) ;
		)*
	};
}

/// Merge multiple [`Array`]s into one combined [`Array`].
///
/// Notice that each component Array's size must be known before hand.
///
/// The macro expects an array list `[a,b,c]` expression with each element
/// being an `Array`.
///
/// The result of this macro will be a single `Array` value that contains
/// the concatination of all vaules from all the given arrays.
///
/// This macro is the reversal of the [`split_array`] macro.
///
///
/// # Syntax
///
/// ```text
/// merge_array!{
///     \[
///         ( <array-vaule> , )*
///     \];
/// }
/// ```
///
/// # Example
///
/// ```
/// use hybrid_array::Array;
/// use hybrid_array::sizes::U2;
/// use hybrid_array::sizes::U4;
/// use array_fusion::merge_array;
///
/// let foo: Array<_, U2> = Array([1, 2]);
/// let bar: Array<_, U4> = Array([0x12, 0x34, 0x56, 0x78]);
///
/// let combi: Array<_,_> = merge_array!(
///     [
///         foo,
///         bar,
///     ]
/// );
///
/// assert_eq!(combi, [
/// 	1, 2, // foo
///     0x12, 0x34, 0x56, 0x78, // bar
/// ]);
/// ```
///
///
///
#[macro_export]
macro_rules! merge_array {
	([
		$( $value:expr ),* $(,)?
	]) => {{
		let empty = $crate::Array::<_ , $crate::sizes::U0>([]);

		empty
		$(
			.concat({
				let value: $crate::Array<_, _> = $value;
				value
			})
		)*
	}};
}

/// Merge core arrays into a combined core array
///
///
///
/// # Example
///
/// ```
/// use array_fusion::merge_core_array;
///
/// let foo: [u8; 2] = [1, 2];
/// let bar: [u8; 4] = [0x12, 0x34, 0x56, 0x78];
///
/// let combi = merge_core_array!(
///     [
///         foo,
///         bar,
///     ]
/// );
///
/// assert_eq!(combi, [
/// 	1, 2, // foo
///     0x12, 0x34, 0x56, 0x78, // bar
/// ]);
/// ```
///
#[macro_export]
macro_rules! merge_core_array {
	([
		$( $value:expr ),* $(,)?
	]) => {
		$crate::array_to_core(
			$crate::merge_array!([
				$(
					$crate::array_from_core(
						$value
					)
				),*
			])
		)
	};
}