heterob/bit_numbering.rs
1/*!
2Bit conversion according to bit numbering
3
4Bit can be converted in 2 ways:
5- Using [FromLsb] / [FromMsb] trait methods `.lsb_into()` / `.msb_into()`
6- Using std [From] trait for wrapper types [Lsb] / [Msb]
7
8## Examples
9It is obligatory to set sizes of resulting values
10
11```rust
12# use heterob::{P3, bit_numbering::*};
13let data = 0b1111_0000_1100_1010;
14
15// Value sizes: ⇓ ⇓ ⇓
16let (a,b,c) = P3::<u16, 7, 1, 8>(data).lsb_into();
17
18let sample = (0b100_1010u64, true, 0xF0u8);
19
20assert_eq!(sample, (a,b,c));
21```
22
23You could ommit source type annotation
24```rust
25# use heterob::{P3, bit_numbering::*};
26let data: u16 = 0b1111_0000_1100_1010;
27
28let Lsb((a,b,c)) = P3::<_, 7, 1, 8>(data).into();
29
30let sample = (0b100_1010u64, true, 0xF0u8);
31
32assert_eq!(sample, (a,b,c));
33```
34
35Ommiting bits using unit type [()](unit)
36```rust
37# use heterob::{P3, bit_numbering::*};
38let data: u16 = 0b1111_0000_0000_1011;
39
40let Lsb(( a, (), b )) = P3::<_, 4, 11, 1>(data).into();
41
42let sample = (0b1011u8, true);
43
44assert_eq!(sample, (a, b));
45```
46
47Explicit type coercion
48```rust
49# use heterob::{P3, bit_numbering::*};
50let data: u16 = 0b1011_0000_0000_1011;
51
52let (a,b,c) = P3::<_, 4, 10, 2>(data).msb_into();
53
54let _: (u16,u32,u64) = (a,b,c);
55
56let sample = (11, 2, 3);
57
58assert_eq!(sample, (a, b, c));
59```
60*/
61
62use core::mem::size_of;
63use paste::paste;
64
65use funty::Integral;
66
67use super::*;
68
69macro_rules! bit_numbering_impl {
70 ($sb:ident => $len:literal: $A:ident $(,)? $($cl:ident),* $(,)?) => { paste!{
71 // impl<TY, A, .. , const AN: usize, .. > FromLsb<P#<TY, .. >> for (A, .. )
72 impl<TY, A, $($cl, )* const AN: usize, $(const [<$cl N>]: usize, )*>
73 [<From $sb>]<[<P $len>]<TY, AN, $([<$cl N>], )*>> for (A, $($cl, )*)
74 where
75 TY: Integral + AsPrimitive<A> $(+ AsPrimitive<$cl>)*,
76 {
77 fn [<from_ $sb:lower>]([<P $len>](_data): [<P $len>]<TY, AN, $([<$cl N>], )*>) -> Self {
78 const {
79 assert!(
80 AN $(+ [<$cl N>])* <= size_of::<Self>() * 8,
81 concat!(
82 "The bits number in TY in ", stringify!([<P $len>]), "<TY, ...>",
83 " is less than sum ", stringify!(AN $(+ [<$cl N>])*),
84 )
85 );
86 }
87
88 let (a, _data) = [<$sb:lower _split>]::<_, AN>(_data);
89 $(
90 let ([<$cl:lower>], _data) = [<$sb:lower _split>]::<_, [<$cl N>]>(_data);
91 )*
92 (a.as_primitive(), $([<$cl:lower>].as_primitive(), )*)
93 }
94 }
95
96 // impl<T, U, const AN: usize, .. > From<P3<T, AN, .. >> for Lsb<U>
97 impl<T, U, const AN: usize, $(const [<$cl N>]: usize, )*>
98 From<[<P $len>]<T, AN, $([<$cl N>], )*>> for $sb<U>
99 where
100 U: [<From $sb>]<[<P $len>]<T, AN, $([<$cl N>], )*>>,
101 {
102 fn from(data: [<P $len>]<T, AN, $([<$cl N>], )*>) -> Self {
103 Self(data.[<$sb:lower _into>]())
104 }
105 }
106 }};
107 ($len:literal: $($cl:ident),+ $(,)?) => {
108 bit_numbering_impl!(Lsb => $len: $($cl),+);
109 bit_numbering_impl!(Msb => $len: $($cl),+);
110 };
111}
112
113/// Type wrapper for LSB 0 bit numbering data
114#[derive(Debug, Clone, PartialEq, Eq)]
115pub struct Lsb<T>(pub T);
116
117/// LSB 0 bit numbering data to value conversion
118///
119/// It is the reciprocal of [LsbInto].
120pub trait FromLsb<T: Sized> {
121 fn from_lsb(_: T) -> Self;
122}
123
124/// LSB 0 bit numbering data to value conversion that consumes the input bytes
125///
126/// The opposite of [FromLsb].
127/// One should avoid implementing [LsbInto] and implement [FromLsb] instead.
128pub trait LsbInto<T>: Sized {
129 fn lsb_into(self) -> T;
130}
131
132/// Implementing [FromLsb] automatically provides one with an implementation of [LsbInto]
133/// thanks to this blanket implementation.
134impl<T, U: FromLsb<T>> LsbInto<U> for T {
135 fn lsb_into(self) -> U {
136 U::from_lsb(self)
137 }
138}
139
140/**
141Split integer at some point according to LSB 0 bit numbering
142
143```rust
144# use heterob::bit_numbering::lsb_split;
145const U32: u32 = 0b1111_1111_0101_1010_1100_001__1_1000_0001;
146let result = lsb_split::<_, 9>(U32);
147assert_eq!((0b1_1000_0001, 0b1111_1111_0101_1010_1100_001), result);
148```
149*/
150pub fn lsb_split<T: Integral, const N: usize>(data: T) -> (T, T) {
151 let mask = !(T::MAX << N);
152 (data & mask, data >> N)
153}
154
155/// Type wrapper for MSB 0 bit numbering data
156#[derive(Debug, Clone, PartialEq, Eq)]
157pub struct Msb<T>(pub T);
158
159/// MSB 0 bit numbering data to value conversion
160///
161/// It is the reciprocal of [MsbInto].
162pub trait FromMsb<T: Sized> {
163 fn from_msb(_: T) -> Self;
164}
165
166/// MSB 0 bit numbering data to value conversion that consumes the input bytes
167///
168/// The opposite of [FromMsb].
169/// One should avoid implementing [MsbInto] and implement [FromMsb] instead.
170pub trait MsbInto<T>: Sized {
171 fn msb_into(self) -> T;
172}
173
174/// Implementing [FromMsb] automatically provides one with an implementation of [MsbInto]
175/// thanks to this blanket implementation.
176impl<T, U: FromMsb<T>> MsbInto<U> for T {
177 fn msb_into(self) -> U {
178 U::from_msb(self)
179 }
180}
181
182/**
183Split integer at some point according to MSB 0 bit numbering
184
185```rust
186# use heterob::bit_numbering::msb_split;
187const U32: u32 = 0b1111_1111_0__101_1010_1100_0011_1000_0001;
188let (a,b) = msb_split::<_, 9>(U32);
189assert_eq!((0b1111_1111_0,0b101_1010_1100_0011_1000_0001 << 9), (a,b), "{a:b},{b:b}");
190```
191*/
192pub fn msb_split<T: Integral, const N: usize>(data: T) -> (T, T) {
193 let mask = T::MAX >> N;
194 ((data & !mask) >> (T::BITS as usize - N), (data & mask) << N)
195}
196
197// // Implemented in [bit_numbering_alphabet]
198// impl<TY, A,B,C, const AN: usize, const BN: usize, const CN: usize> FromLsb<P3<TY,AN,BN,CN>> for (A,B,C)
199// where
200// TY: Integral + AsPrimitive<A> + AsPrimitive<B> + AsPrimitive<C>,
201// {
202// const BITS: usize = TY::BITS as usize;
203// const MAX_BIT_INDEX: usize = AN + BN + CN;
204// fn from_lsb(P3(_data): P3<TY,AN,BN,CN>) -> Self {
205// #![allow(path_statements)]
206// <Self as FromLsb<P3<TY, AN,BN,CN>>>::ASSERT_INDEX_IN_BOUNDS;
207
208// let (a, _data) = lsb_split::<_, AN>(_data);
209// let (b, _data) = lsb_split::<_, BN>(_data);
210// let (c, _data) = lsb_split::<_, CN>(_data);
211// (a.as_primitive(), b.as_primitive(), c.as_primitive())
212// }
213// }
214
215// // Implemented in [bit_numbering_alphabet]
216// impl<T, U, const AN: usize, const BN: usize, const CN: usize> From<P3<T, AN, BN, CN>> for Lsb<U>
217// where
218// U: FromLsb<P3<T,AN,BN,CN>>,
219// {
220// fn from(data: P3<T,AN,BN,CN>) -> Self {
221// Self(data.lsb_into())
222// }
223// }
224
225bit_numbering_impl!(1: A);
226bit_numbering_impl!(2: A,B);
227bit_numbering_impl!(3: A,B,C);
228bit_numbering_impl!(4: A,B,C,D);
229bit_numbering_impl!(5: A,B,C,D,E);
230bit_numbering_impl!(6: A,B,C,D,E,F);
231bit_numbering_impl!(7: A,B,C,D,E,F,G);
232bit_numbering_impl!(8: A,B,C,D,E,F,G,H);
233bit_numbering_impl!(9: A,B,C,D,E,F,G,H,I);
234bit_numbering_impl!(10: A,B,C,D,E,F,G,H,I,J);
235bit_numbering_impl!(11: A,B,C,D,E,F,G,H,I,J,K);
236bit_numbering_impl!(12: A,B,C,D,E,F,G,H,I,J,K,L);
237bit_numbering_impl!(13: A,B,C,D,E,F,G,H,I,J,K,L,M);
238bit_numbering_impl!(14: A,B,C,D,E,F,G,H,I,J,K,L,M,N);
239bit_numbering_impl!(15: A,B,C,D,E,F,G,H,I,J,K,L,M,N,O);
240bit_numbering_impl!(16: A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P);
241bit_numbering_impl!(17: A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q);
242bit_numbering_impl!(18: A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R);
243bit_numbering_impl!(19: A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S);
244bit_numbering_impl!(20: A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T);
245bit_numbering_impl!(21: A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U);
246bit_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);
247bit_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);
248bit_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);
249bit_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);
250bit_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);
251
252#[cfg(test)]
253mod tests {
254 use super::*;
255
256 const U32: u32 = 0b1111_1111_0101_1010_1100_0011_1000_0001;
257
258 #[test]
259 fn trait_lsb_into_tuple() {
260 let (a, b, c, ()) = P4::<_, 15, 1, 2, 14>(U32).lsb_into();
261 let _: (u16, bool, u8) = (a, b, c);
262 assert_eq!(
263 (0b100_0011_1000_0001, true, 0b10),
264 (a, b, c),
265 "{a:b}, {b}, {c:b}"
266 );
267 }
268
269 #[test]
270 fn trait_msb_into_tuple() {
271 let (a, b, c) = P3::<_, 15, 1, 2>(U32).msb_into();
272 let _: (u16, bool, u8) = (a, b, c);
273 assert_eq!(
274 (0b1111_1111_0101_101, false, 0b11),
275 (a, b, c),
276 "{a:b}, {b}, {c:b}"
277 );
278 }
279
280 #[test]
281 fn struct_lsb_into_tuple() {
282 let Lsb((a, b, c, ())) = P4::<_, 15, 1, 2, 14>(U32).into();
283 let _: (u16, bool, u8) = (a, b, c);
284 assert_eq!(
285 (0b100_0011_1000_0001, true, 0b10),
286 (a, b, c),
287 "{a:b}, {b}, {c:b}"
288 );
289 }
290
291 #[test]
292 fn struct_msb_into_tuple() {
293 let Msb((a, b, c)) = P3::<_, 15, 1, 2>(U32).into();
294 let _: (u16, bool, u8) = (a, b, c);
295 assert_eq!(
296 (0b1111_1111_0101_101, false, 0b11),
297 (a, b, c),
298 "{a:b}, {b}, {c:b}"
299 );
300 }
301}