Skip to content

Commit

Permalink
feat(bitfield): add u128 support (#467)
Browse files Browse the repository at this point in the history
This branch adds support for `u128` as a representation for the
`bitfield!` macro, and packing specs for 128-bit numbers.

Closes #466
  • Loading branch information
hawkw authored Nov 28, 2023
1 parent 29941e4 commit 54871d4
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 14 deletions.
35 changes: 32 additions & 3 deletions bitfield/src/bitfield.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
/// # Generated Implementations
///
/// The `bitfield!` macro generates a type with the following functions, where
/// `{int}` is the integer type that represents the bitfield (one of `u8`,
/// `u16`,`u32`, `u64`, or `usize`):
/// `{int}` is the integer type that represents the bitfield (one of [`u8`],
/// [`u16`], [`u32`], [`u64`], [`u128`], or [`usize`]):
///
/// - `const fn new() -> Self`: Returns a new instance of the bitfield type with
/// all bits zeroed.
Expand Down Expand Up @@ -833,11 +833,12 @@ macro_rules! bitfield {
// };

(@t usize, $V:ty, $F:ty) => { $crate::PackUsize<$V, $F> };
(@t u128, $V:ty, $F:ty) => { $crate::Pack128<$V, $F> };
(@t u64, $V:ty, $F:ty) => { $crate::Pack64<$V, $F> };
(@t u32, $V:ty, $F:ty) => { $crate::Pack32<$V, $F> };
(@t u16, $V:ty, $F:ty) => { $crate::Pack16<$V, $F> };
(@t u8, $V:ty, $F:ty) => { $crate::Pack8<$V, $F> };
(@t $T:ty, $V:ty, $F:ty) => { compile_error!(concat!("unsupported bitfield type `", stringify!($T), "`; expected one of `usize`, `u64`, `u32`, `u16`, or `u8`")) }
(@t $T:ty, $V:ty, $F:ty) => { compile_error!(concat!("unsupported bitfield type `", stringify!($T), "`; expected one of `usize`, `u128`, `u64`, `u32`, `u16`, or `u8`")) }
}

#[cfg(test)]
Expand All @@ -857,6 +858,21 @@ mod tests {
}
}

bitfield! {
/// This is only here to ensure it compiles...
#[allow(dead_code)]
struct TestBitfieldHuge<u128> {
const HELLO = 4;
const _RESERVED_1 = 3;
const WORLD: bool;
const HAVE: TestEnum;
const LOTS = 5;
const OF = 1;
const FUN = 6;
const REST = ..;
}
}

#[repr(u8)]
#[derive(Debug)]
enum TestEnum {
Expand Down Expand Up @@ -885,6 +901,19 @@ mod tests {
}
}

impl FromBits<u128> for TestEnum {
const BITS: u32 = 2;
type Error = core::convert::Infallible;

fn try_from_bits(bits: u128) -> Result<Self, Self::Error> {
FromBits::<u32>::try_from_bits(bits as u32)
}

fn into_bits(self) -> u128 {
self as u8 as u128
}
}

#[derive(Debug)]
#[allow(dead_code)]
struct TestDebug {
Expand Down
20 changes: 11 additions & 9 deletions bitfield/src/from_bits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -337,19 +337,20 @@ macro_rules! impl_frombits_for_bool {
}

impl_frombits_for_bool! {
impl FromBits<u8, u16, u32, u64, usize> for bool {}
impl FromBits<u8, u16, u32, u64, u128, usize> for bool {}
}

impl_frombits_for_ty! {
impl FromBits<u8, u16, u32, u64> for u8 {}
impl FromBits<u16, u32, u64> for u16 {}
impl FromBits<u32, u64> for u32 {}
impl FromBits<u64> for u64 {}
impl FromBits<u8, u16, u32, u64, u128> for u8 {}
impl FromBits<u16, u32, u64, u128> for u16 {}
impl FromBits<u32, u64, u128> for u32 {}
impl FromBits<u64, u128> for u64 {}
impl FromBits<u128> for u128 {}

impl FromBits<u8, u16, u32, u64> for i8 {}
impl FromBits<u16, u32, u64> for i16 {}
impl FromBits<u32, u64> for i32 {}
impl FromBits<u64> for i64 {}
impl FromBits<u8, u16, u32, u64, u128> for i8 {}
impl FromBits<u16, u32, u64, u128> for i16 {}
impl FromBits<u32, u64, u128> for i32 {}
impl FromBits<u64, u128> for i64 {}

// Rust doesn't support 8 bit targets, so {u,i}size are always at least 16 bit wide,
// source: https://doc.rust-lang.org/1.45.2/src/core/convert/num.rs.html#134-139
Expand All @@ -363,6 +364,7 @@ impl_frombits_for_ty! {

impl FromBits<usize> for usize {}
impl FromBits<usize> for isize {}
impl FromBits<u128> for usize {}
}

#[cfg(target_pointer_width = "16")]
Expand Down
13 changes: 11 additions & 2 deletions bitfield/src/pack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
//! The bit packing utilities consist of a type that defines a specification for
//! a bit range to pack into, and a wrapper type for an unsigned integer
//! defining methods to pack bit ranges into it. Packing specs are defined for
//! [`u64`], [`u32`], [`u16`], and [`u8`], as [`Pack64`], [`Pack32`],
//! [`Pack16`], and [`Pack8`], respectively.
//! [`usize`], [`u128`], [`u64`], [`u32`], [`u16`], and [`u8`], as
//! [`PackUsize`], [`Pack128`], [`Pack64`], [`Pack32`], [`Pack16`], and
//! [`Pack8`], respectively.
//!
//! Note that the bit packing utilities are generic using macros, rather than
//! using generics and traits, because they are intended to be usable in
Expand Down Expand Up @@ -1079,6 +1080,7 @@ macro_rules! make_packers {

make_packers! {
pub struct PackUsize { bits: usize, packing: PackingUsize, pair: PairUsize }
pub struct Pack128 { bits: u128, packing: Packing128, pair: Pair128 }
pub struct Pack64 { bits: u64, packing: Packing64, pair: Pair64, }
pub struct Pack32 { bits: u32, packing: Packing32, pair: Pair32, }
pub struct Pack16 { bits: u16, packing: Packing16, pair: Pair16, }
Expand Down Expand Up @@ -1281,34 +1283,41 @@ mod tests {
}

test_pack_unpack! {
fn pack_unpack_128<Pack128, u128>(128);
fn pack_unpack_64<Pack64, u64>(64);
fn pack_unpack_32<Pack32, u32>(32);
fn pack_unpack_16<Pack16, u16>(16);
fn pack_unpack_8<Pack8, u8>(8);
}

test_pack_methods! {

fn pack_methods_128<Pack128, u128>(128);
fn pack_methods_64<Pack64, u64>(64);
fn pack_methods_32<Pack32, u32>(32);
fn pack_methods_16<Pack16, u16>(16);
fn pack_methods_8<Pack8, u8>(8);
}

test_from_range! {
fn pack_from_src_range_128<Pack128, u128>(128);
fn pack_from_src_range_64<Pack64, u64>(64);
fn pack_from_src_range_32<Pack32, u32>(32);
fn pack_from_src_range_16<Pack16, u16>(16);
fn pack_from_src_range_8<Pack8, u8>(8);
}

test_pair_least_sig_zeroed! {

fn pair_least_sig_zeroed_128<Pack128, u128>(128);
fn pair_least_sig_zeroed_64<Pack64, u64>(64);
fn pair_least_sig_zeroed_32<Pack32, u32>(32);
fn pair_least_sig_zeroed_16<Pack16, u16>(16);
fn pair_least_sig_zeroed_8<Pack8, u8>(8);
}

test_pair_least_sig_arbitrary! {
fn pair_least_sig_arbitrary_128<Pack128, u128>(128);
fn pair_least_sig_arbitrary_64<Pack64, u64>(64);
fn pair_least_sig_arbitrary_32<Pack32, u32>(32);
fn pair_least_sig_arbitrary_16<Pack16, u16>(16);
Expand Down

0 comments on commit 54871d4

Please sign in to comment.