use core::ops::Add;
use core::ops::Mul;
pub use hybrid_array;
#[doc(hidden)]
pub use hybrid_array::Array;
use hybrid_array::ArraySize;
use hybrid_array::AssocArraySize;
#[doc(hidden)]
pub use hybrid_array::sizes;
use hybrid_array::sizes::U0;
use hybrid_array::sizes::U1;
use hybrid_array::typenum::Prod;
use hybrid_array::typenum::Sum;
use super::SizeOf;
use crate::array_from_core;
use crate::chunks::flatten;
#[macro_export]
macro_rules! merge_bytes {
(
[
$($name:ident),* $(,)?
]
) => {{
$(
let $name = $crate::bytes::encoding::IntoByteArray::into_bytes($name) ;
)*
$crate::merge_array!(
[
$($name),*
]
)
}};
}
pub trait IntoByteArray {
type Size: ArraySize;
fn into_bytes(self) -> Array<u8, Self::Size>;
}
impl<Size, T> IntoByteArray for Array<T, Size>
where
Size: ArraySize,
T: IntoByteArray,
Prod<T::Size, Size>: ArraySize,
T::Size: Mul<Size>,
{
type Size = Prod<T::Size, Size>;
fn into_bytes(self) -> Array<u8, Self::Size> {
flatten(self.map(|sub| sub.into_bytes()))
}
}
impl<const N: usize, T> IntoByteArray for [T; N]
where
T: IntoByteArray,
[T; N]: AssocArraySize,
<[T; N] as AssocArraySize>::Size: ArraySize<ArrayType<T> = [T; N]>,
Prod<T::Size, SizeOf<T, N>>: ArraySize,
T::Size: Mul<SizeOf<T, N>>,
{
type Size = Prod<T::Size, SizeOf<T, N>>;
fn into_bytes(self) -> Array<u8, Self::Size> {
array_from_core(self).into_bytes()
}
}
impl IntoByteArray for u8 {
type Size = U1;
fn into_bytes(self) -> Array<u8, Self::Size> {
Array([self])
}
}
impl IntoByteArray for i8 {
type Size = U1;
fn into_bytes(self) -> Array<u8, Self::Size> {
Array([self as u8])
}
}
impl IntoByteArray for bool {
type Size = U1;
fn into_bytes(self) -> Array<u8, Self::Size> {
Array([self as u8])
}
}
impl IntoByteArray for () {
type Size = U0;
fn into_bytes(self) -> Array<u8, Self::Size> {
Array([])
}
}
impl<T1> IntoByteArray for (T1,)
where
T1: IntoByteArray,
{
type Size = T1::Size;
fn into_bytes(self) -> Array<u8, Self::Size> {
self.0.into_bytes()
}
}
impl<T1, T2> IntoByteArray for (T1, T2)
where
T1: IntoByteArray,
T2: IntoByteArray,
Sum<T1::Size, T2::Size>: ArraySize,
T1::Size: Add<T2::Size>,
{
type Size = Sum<T1::Size, T2::Size>;
fn into_bytes(self) -> Array<u8, Self::Size> {
let (a, b) = self;
let a = a.into_bytes();
let b = b.into_bytes();
a.concat(b)
}
}
pub fn merge_into_bytes<T>(value: T) -> Array<u8, T::Size>
where
T: IntoByteArray,
{
value.into_bytes()
}
#[cfg(test)]
mod test {
use hybrid_array::sizes::U2;
use hybrid_array::sizes::U4;
use super::*;
use crate::array_from_core;
use crate::bytes::BigEndian;
struct Foo(u16);
impl IntoByteArray for Foo {
type Size = U2;
fn into_bytes(self) -> Array<u8, Self::Size> {
BigEndian(self.0).into_bytes()
}
}
struct Bar(u32);
impl IntoByteArray for Bar {
type Size = U4;
fn into_bytes(self) -> Array<u8, Self::Size> {
BigEndian(self.0).into_bytes()
}
}
#[test]
fn test_merge_bytes_u8() {
let input = 42_u8;
let output = merge_into_bytes(input);
assert_eq!(output, Array([42]));
}
#[test]
fn test_merge_bytes_id() {
let input = Array::<u8, U4>([1, 2, 3, 4]);
let output = merge_into_bytes(input);
assert_eq!(output, input);
}
#[test]
fn test_merge_bytes_array() {
let input = [1, 2, 3, 4_u8];
let output = merge_into_bytes(input);
assert_eq!(output, Array([1, 2, 3, 4]));
}
#[test]
fn test_merge_bytes_array_of_arrays() {
let input = [[1, 2], [3, 4_u8]];
let data = array_from_core(input);
let output = merge_into_bytes(data);
assert_eq!(output, Array([1, 2, 3, 4]));
}
#[test]
fn test_merge_bytes_tuple() {
let input = (1_u8, 2_u8);
let output = merge_into_bytes(input);
assert_eq!(output, Array([1, 2]));
}
#[test]
fn test_merge_bytes_custom_type() {
let input = Foo(42);
let output = merge_into_bytes(input);
assert_eq!(output, Array([0, 42]));
}
#[test]
fn test_merge_bytes_custom_tuple() {
let input = (Foo(42), Bar(0x1234));
let output = merge_into_bytes(input);
assert_eq!(output, Array([0, 42, 0x0, 0x0, 0x12, 0x34]));
}
#[test]
fn test_merge_bytes() {
let foo = Foo(42);
let bar = Bar(0x1234);
let padding = 0_u8;
let alpha = *b"abc";
let data = merge_bytes!([foo, bar, padding, alpha]);
assert_eq!(
data,
Array([
0, 42, 0x0, 0x0, 0x12, 0x34, 0, b'a', b'b', b'c', ])
);
}
}