bitpiece/
storage.rs

1use core::num::TryFromIntError;
2
3use crate::*;
4
5/// a type which can be used as the internal storage of a bitpiece.
6pub trait BitStorage: BitPiece {
7    const ZEROES: Self;
8    const ONES: Self;
9
10    /// the signed version of this storage integer type.
11    type Signed;
12
13    fn to_u64(self) -> u64;
14    fn from_u64(value: u64) -> Result<Self, TryFromIntError>;
15}
16
17impl BitStorage for u64 {
18    const ZEROES: Self = 0;
19    const ONES: Self = u64::MAX;
20
21    type Signed = i64;
22
23    fn to_u64(self) -> u64 {
24        self
25    }
26
27    fn from_u64(value: u64) -> Result<Self, TryFromIntError> {
28        Ok(value)
29    }
30}
31
32macro_rules! impl_bit_storage_for_small_unsigned_int_types {
33    { $($bit_len: literal),+ } => {
34        $(
35            paste::paste! {
36                impl BitStorage for [<u $bit_len>] {
37                    const ZEROES: Self = 0;
38                    const ONES: Self = Self::MAX;
39                    type Signed = [<i $bit_len>];
40                    fn to_u64(self) -> u64 {
41                        self as u64
42                    }
43                    fn from_u64(value: u64) -> Result<Self, TryFromIntError> {
44                        value.try_into()
45                    }
46                }
47            }
48        )+
49    };
50}
51impl_bit_storage_for_small_unsigned_int_types! { 8, 16, 32 }
52
53/// an empty struct used to represent a specific bit length.
54/// this is then combined with some traits ([`ExactAssociatedStorage`], [`AssociatedStorage`]) to perform operations on the
55/// specified bit length.
56pub struct BitLength<const BITS: usize>;
57
58/// a trait implemented for [`BitLength`] types that have an exact associated storage type, for example [`u8`] or [`u16`].
59pub trait ExactAssociatedStorage {
60    /// the exact storage type, for example [`u8`] or [`u16`].
61    type Storage: BitStorage;
62}
63
64/// a trait implemented for all [`BitLength`] types that are small enough and provides the minimal storage type required for
65/// storing that amount of bits. for example for bit lengths `0..8` this will be [`u8`].
66pub trait AssociatedStorage {
67    /// the storage type required for storing that amount of bits. for example for bit lengths `0..8` this will be [`u8`].
68    type Storage: BitStorage;
69}
70
71macro_rules! impl_exact_associated_storage {
72    { $($bit_length: literal),+ $(,)? } => {
73        $(
74            paste::paste! {
75                impl ExactAssociatedStorage for BitLength<$bit_length> {
76                    type Storage = [<u $bit_length>];
77                }
78            }
79        )+
80    }
81}
82impl_exact_associated_storage! { 8, 16, 32, 64 }
83
84/// calculate the bit length of the smallest type required to store that amount of bits. for example for bits lengths `1..=8` this
85/// will return `8`.
86const fn exact_associated_storage_bit_length(bit_length: usize) -> usize {
87    if bit_length == 0 {
88        panic!("bit length can't be 0");
89    }
90    let power_of_2 = bit_length.next_power_of_two();
91    if power_of_2 < 8 {
92        8
93    } else {
94        power_of_2
95    }
96}
97macro_rules! impl_associated_storage {
98    { $($bit_length: literal),+ $(,)? } => {
99        $(
100            impl AssociatedStorage for BitLength<$bit_length> {
101                type Storage = <BitLength< { exact_associated_storage_bit_length($bit_length) } > as ExactAssociatedStorage>::Storage;
102            }
103        )+
104    };
105}
106impl_associated_storage! {
107    1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
108    34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
109}