use core::mem::size_of;
use paste::paste;
use funty::Integral;
use super::*;
macro_rules! bit_numbering_impl {
($sb:ident => $len:literal: $A:ident $(,)? $($cl:ident),* $(,)?) => { paste!{
impl<TY, A, $($cl, )* const AN: usize, $(const [<$cl N>]: usize, )*>
[<From $sb>]<[<P $len>]<TY, AN, $([<$cl N>], )*>> for (A, $($cl, )*)
where
TY: Integral + AsPrimitive<A> $(+ AsPrimitive<$cl>)*,
{
fn [<from_ $sb:lower>]([<P $len>](_data): [<P $len>]<TY, AN, $([<$cl N>], )*>) -> Self {
const {
assert!(
AN $(+ [<$cl N>])* <= size_of::<Self>() * 8,
concat!(
"The bits number in TY in ", stringify!([<P $len>]), "<TY, ...>",
" is less than sum ", stringify!(AN $(+ [<$cl N>])*),
)
);
}
let (a, _data) = [<$sb:lower _split>]::<_, AN>(_data);
$(
let ([<$cl:lower>], _data) = [<$sb:lower _split>]::<_, [<$cl N>]>(_data);
)*
(a.as_primitive(), $([<$cl:lower>].as_primitive(), )*)
}
}
impl<T, U, const AN: usize, $(const [<$cl N>]: usize, )*>
From<[<P $len>]<T, AN, $([<$cl N>], )*>> for $sb<U>
where
U: [<From $sb>]<[<P $len>]<T, AN, $([<$cl N>], )*>>,
{
fn from(data: [<P $len>]<T, AN, $([<$cl N>], )*>) -> Self {
Self(data.[<$sb:lower _into>]())
}
}
}};
($len:literal: $($cl:ident),+ $(,)?) => {
bit_numbering_impl!(Lsb => $len: $($cl),+);
bit_numbering_impl!(Msb => $len: $($cl),+);
};
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Lsb<T>(pub T);
pub trait FromLsb<T: Sized> {
fn from_lsb(_: T) -> Self;
}
pub trait LsbInto<T>: Sized {
fn lsb_into(self) -> T;
}
impl<T, U: FromLsb<T>> LsbInto<U> for T {
fn lsb_into(self) -> U {
U::from_lsb(self)
}
}
pub fn lsb_split<T: Integral, const N: usize>(data: T) -> (T, T) {
let mask = !(T::MAX << N);
(data & mask, data >> N)
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Msb<T>(pub T);
pub trait FromMsb<T: Sized> {
fn from_msb(_: T) -> Self;
}
pub trait MsbInto<T>: Sized {
fn msb_into(self) -> T;
}
impl<T, U: FromMsb<T>> MsbInto<U> for T {
fn msb_into(self) -> U {
U::from_msb(self)
}
}
pub fn msb_split<T: Integral, const N: usize>(data: T) -> (T, T) {
let mask = T::MAX >> N;
((data & !mask) >> (T::BITS as usize - N), (data & mask) << N)
}
bit_numbering_impl!(1: A);
bit_numbering_impl!(2: A,B);
bit_numbering_impl!(3: A,B,C);
bit_numbering_impl!(4: A,B,C,D);
bit_numbering_impl!(5: A,B,C,D,E);
bit_numbering_impl!(6: A,B,C,D,E,F);
bit_numbering_impl!(7: A,B,C,D,E,F,G);
bit_numbering_impl!(8: A,B,C,D,E,F,G,H);
bit_numbering_impl!(9: A,B,C,D,E,F,G,H,I);
bit_numbering_impl!(10: A,B,C,D,E,F,G,H,I,J);
bit_numbering_impl!(11: A,B,C,D,E,F,G,H,I,J,K);
bit_numbering_impl!(12: A,B,C,D,E,F,G,H,I,J,K,L);
bit_numbering_impl!(13: A,B,C,D,E,F,G,H,I,J,K,L,M);
bit_numbering_impl!(14: A,B,C,D,E,F,G,H,I,J,K,L,M,N);
bit_numbering_impl!(15: A,B,C,D,E,F,G,H,I,J,K,L,M,N,O);
bit_numbering_impl!(16: A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P);
bit_numbering_impl!(17: A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q);
bit_numbering_impl!(18: A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R);
bit_numbering_impl!(19: A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S);
bit_numbering_impl!(20: A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T);
bit_numbering_impl!(21: A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U);
bit_numbering_impl!(22: A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V);
bit_numbering_impl!(23: A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W);
bit_numbering_impl!(24: A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X);
bit_numbering_impl!(25: A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y);
bit_numbering_impl!(26: A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z);
#[cfg(test)]
mod tests {
use super::*;
const U32: u32 = 0b1111_1111_0101_1010_1100_0011_1000_0001;
#[test]
fn trait_lsb_into_tuple() {
let (a, b, c, ()) = P4::<_, 15, 1, 2, 14>(U32).lsb_into();
let _: (u16, bool, u8) = (a, b, c);
assert_eq!(
(0b100_0011_1000_0001, true, 0b10),
(a, b, c),
"{a:b}, {b}, {c:b}"
);
}
#[test]
fn trait_msb_into_tuple() {
let (a, b, c) = P3::<_, 15, 1, 2>(U32).msb_into();
let _: (u16, bool, u8) = (a, b, c);
assert_eq!(
(0b1111_1111_0101_101, false, 0b11),
(a, b, c),
"{a:b}, {b}, {c:b}"
);
}
#[test]
fn struct_lsb_into_tuple() {
let Lsb((a, b, c, ())) = P4::<_, 15, 1, 2, 14>(U32).into();
let _: (u16, bool, u8) = (a, b, c);
assert_eq!(
(0b100_0011_1000_0001, true, 0b10),
(a, b, c),
"{a:b}, {b}, {c:b}"
);
}
#[test]
fn struct_msb_into_tuple() {
let Msb((a, b, c)) = P3::<_, 15, 1, 2>(U32).into();
let _: (u16, bool, u8) = (a, b, c);
assert_eq!(
(0b1111_1111_0101_101, false, 0b11),
(a, b, c),
"{a:b}, {b}, {c:b}"
);
}
}