use crate::{
access::BitAccess,
order::{
Lsb0,
Msb0,
},
slice::BitSlice,
store::BitStore,
};
use core::{
cmp,
mem,
ptr,
};
use either::Either;
#[cfg(feature = "alloc")]
use crate::{
boxed::BitBox,
order::BitOrder,
vec::BitVec,
};
pub trait BitField {
fn load<U>(&self) -> U
where U: BitStore {
#[cfg(target_endian = "little")]
return self.load_le();
#[cfg(target_endian = "big")]
return self.load_be();
}
fn load_le<U>(&self) -> U
where U: BitStore;
fn load_be<U>(&self) -> U
where U: BitStore;
fn store<U>(&mut self, value: U)
where U: BitStore {
#[cfg(target_endian = "little")]
self.store_le(value);
#[cfg(target_endian = "big")]
self.store_be(value);
}
fn store_le<U>(&mut self, value: U)
where U: BitStore;
fn store_be<U>(&mut self, value: U)
where U: BitStore;
}
impl<T> BitField for BitSlice<Lsb0, T>
where T: BitStore {
fn load_le<U>(&self) -> U
where U: BitStore {
let len = self.len();
if !(1 ..= U::BITS as usize).contains(&len) {
panic!("Cannot load {} bits from a {}-bit region", U::BITS, len);
}
match self.bitptr().domain().splat() {
Either::Right((head, elt, _)) =>
resize((elt.load() >> *head) & mask_for::<T>(len)),
Either::Left((head, body, tail)) => {
let mut accum = 0usize;
if let Some((tail, t)) = tail {
accum = resize(tail.load() & mask_for::<T>(*t as usize));
}
if let Some(elts) = body {
for elt in elts.iter().rev() {
let val: usize = resize(elt.load());
accum <<= T::BITS;
accum |= val;
}
}
if let Some((h, head)) = head {
let lsedge = *h;
let width = T::BITS - lsedge;
let val: usize = resize(head.load() >> lsedge);
accum <<= width;
accum |= val;
}
resize(accum)
},
}
}
fn load_be<U>(&self) -> U
where U: BitStore {
let len = self.len();
if !(1 ..= U::BITS as usize).contains(&len) {
panic!("Cannot load {} bits from a {}-bit region", U::BITS, len);
}
match self.bitptr().domain().splat() {
Either::Right((head, elt, _)) =>
resize((elt.load() >> *head) & mask_for::<T>(len)),
Either::Left((head, body, tail)) => {
let mut accum = 0usize;
if let Some((h, head)) = head {
accum = resize(head.load() >> *h);
}
if let Some(elts) = body {
for elt in elts.iter() {
let val: usize = resize(elt.load());
accum <<= T::BITS;
accum |= val;
}
}
if let Some((tail, t)) = tail {
let width = *t as usize;
let val: usize = resize(tail.load() & mask_for::<T>(width));
accum <<= width;
accum |= val;
}
resize(accum)
},
}
}
fn store_le<U>(&mut self, value: U)
where U: BitStore {
let len = self.len();
if !(1 ..= U::BITS as usize).contains(&len) {
panic!("Cannot store {} bits in a {}-bit region", U::BITS, len);
}
let value = value & mask_for(len);
match self.bitptr().domain().splat() {
Either::Right((head, elt, _)) => {
let lsedge = *head;
elt.clear_bits(!(mask_for::<T>(len) << lsedge));
elt.set_bits(resize::<U, T>(value) << lsedge);
},
Either::Left((head, body, tail)) => {
let mut value: usize = resize(value);
if let Some((h, head)) = head {
let lsedge = *h;
let width = T::BITS - lsedge;
let val = value & mask_for::<usize>(width as usize);
head.clear_bits(T::TRUE >> width);
head.set_bits(resize::<usize, T>(val) << lsedge);
value >>= width;
}
if let Some(elts) = body {
for elt in elts.iter() {
elt.store(resize(value));
value >>= T::BITS;
}
}
if let Some((tail, t)) = tail {
let width = *t;
let val = value & mask_for::<usize>(width as usize);
tail.clear_bits(T::TRUE << width);
tail.set_bits(resize(val));
}
},
}
}
fn store_be<U>(&mut self, value: U)
where U: BitStore {
let len = self.len();
if !(1 ..= U::BITS as usize).contains(&len) {
panic!("Cannot store {} bits in a {}-bit region", U::BITS, len);
}
let value = value & mask_for(len);
match self.bitptr().domain().splat() {
Either::Right((head, elt, _)) => {
let lsedge = *head;
elt.clear_bits(!(mask_for::<T>(len) << lsedge));
elt.set_bits(resize::<U, T>(value) << lsedge);
},
Either::Left((head, body, tail)) => {
let mut value: usize = resize(value);
if let Some((tail, t)) = tail {
let width = *t;
let val = value & mask_for::<usize>(width as usize);
tail.clear_bits(T::TRUE << width);
tail.set_bits(resize(val));
value >>= width;
}
if let Some(elts) = body {
for elt in elts.iter().rev() {
elt.store(resize(value));
value >>= T::BITS;
}
}
if let Some((h, head)) = head {
let lsedge = *h;
let width = T::BITS - lsedge;
let val = value & mask_for::<usize>(width as usize);
head.clear_bits(T::TRUE >> width);
head.set_bits(resize::<usize, T>(val) << lsedge);
}
},
}
}
}
impl<T> BitField for BitSlice<Msb0, T>
where T: BitStore {
fn load_le<U>(&self) -> U
where U: BitStore {
let len = self.len();
if !(1 ..= U::BITS as usize).contains(&len) {
panic!("Cannot load {} bits from a {}-bit region", U::BITS, len);
}
match self.bitptr().domain().splat() {
Either::Right((_, elt, tail)) =>
resize((elt.load() >> (T::BITS - *tail)) & mask_for::<T>(len)),
Either::Left((head, body, tail)) => {
let mut accum = 0usize;
if let Some((tail, t)) = tail {
let lsedge = T::BITS - *t;
accum = resize(tail.load() >> lsedge);
}
if let Some(elts) = body {
for elt in elts.iter().rev() {
let val: usize = resize(elt.load());
accum <<= T::BITS;
accum |= val;
}
}
if let Some((h, head)) = head {
let width = (T::BITS - *h) as usize;
let val: usize = resize(head.load() & mask_for::<T>(width));
accum <<= width;
accum |= val;
}
resize(accum)
},
}
}
fn load_be<U>(&self) -> U
where U: BitStore {
let len = self.len();
if !(1 ..= U::BITS as usize).contains(&len) {
panic!("Cannot load {} bits from a {}-bit region", U::BITS, len);
}
match self.bitptr().domain().splat() {
Either::Right((_, elt, tail)) =>
resize((elt.load() >> (T::BITS - *tail)) & mask_for::<T>(len)),
Either::Left((head, body, tail)) => {
let mut accum = 0usize;
if let Some((h, head)) = head {
let width = T::BITS - *h;
accum = resize(head.load() & mask_for::<T>(width as usize));
}
if let Some(elts) = body {
for elt in elts.iter() {
let val: usize = resize(elt.load());
accum <<= T::BITS;
accum |= val;
}
}
if let Some((tail, t)) = tail {
let lsedge = T::BITS - *t;
let val: usize = resize(tail.load() >> lsedge);
accum <<= *t;
accum |= val;
}
resize(accum)
},
}
}
fn store_le<U>(&mut self, value: U)
where U: BitStore {
let len = self.len();
if !(1 ..= U::BITS as usize).contains(&len) {
panic!("Cannot store {} bits in a {}-bit region", U::BITS, len);
}
let value = value & mask_for(len);
match self.bitptr().domain().splat() {
Either::Right((_, elt, tail)) => {
let lsedge = T::BITS - *tail;
elt.clear_bits(!(mask_for::<T>(len) << lsedge));
elt.set_bits(resize::<U, T>(value) << lsedge);
},
Either::Left((head, body, tail)) => {
let mut value: usize = resize(value);
if let Some((h, head)) = head {
let width = T::BITS - *h;
let val = value & mask_for::<usize>(width as usize);
head.clear_bits(T::TRUE << width);
head.set_bits(resize(val));
value >>= width;
}
if let Some(elts) = body {
for elt in elts.iter() {
elt.store(resize(value));
value >>= T::BITS;
}
}
if let Some((tail, t)) = tail {
let width = *t;
let lsedge = T::BITS - width;
let val = value & mask_for::<usize>(width as usize);
tail.clear_bits(T::TRUE >> width);
tail.set_bits(resize::<usize, T>(val) << lsedge);
}
},
}
}
fn store_be<U>(&mut self, value: U)
where U: BitStore {
let len = self.len();
if !(1 ..= U::BITS as usize).contains(&len) {
panic!("Cannot store {} bits in a {}-bit region", U::BITS, len);
}
let value = value & mask_for(len);
match self.bitptr().domain().splat() {
Either::Right((_, elt, tail)) => {
let lsedge = T::BITS - *tail;
elt.clear_bits(!(mask_for::<T>(len) << lsedge));
elt.set_bits(resize::<U, T>(value) << lsedge);
},
Either::Left((head, body, tail)) => {
let mut value: usize = resize(value);
if let Some((tail, t)) = tail {
let width = *t;
let lsedge = T::BITS - width;
let val = value & mask_for::<usize>(width as usize);
tail.clear_bits(T::TRUE >> width);
tail.set_bits(resize::<usize, T>(val) << lsedge);
value >>= width;
}
if let Some(elts) = body {
for elt in elts.iter().rev() {
elt.store(resize(value));
value >>= T::BITS;
}
}
if let Some((h, head)) = head {
let width = T::BITS - *h;
let val = value & mask_for::<usize>(width as usize);
head.clear_bits(T::TRUE << width);
head.set_bits(resize(val));
}
},
}
}
}
#[cfg(feature = "alloc")]
impl<O, T> BitField for BitBox<O, T>
where O: BitOrder, T: BitStore, BitSlice<O, T>: BitField {
fn load_le<U>(&self) -> U
where U: BitStore {
self.as_bitslice().load_le()
}
fn load_be<U>(&self) -> U
where U: BitStore {
self.as_bitslice().load_be()
}
fn store_le<U>(&mut self, value: U)
where U: BitStore {
self.as_mut_bitslice().store_le(value)
}
fn store_be<U>(&mut self, value: U)
where U: BitStore {
self.as_mut_bitslice().store_be(value)
}
}
#[cfg(feature = "alloc")]
impl<O, T> BitField for BitVec<O, T>
where O: BitOrder, T: BitStore, BitSlice<O, T>: BitField {
fn load_le<U>(&self) -> U
where U: BitStore {
self.as_bitslice().load_le()
}
fn load_be<U>(&self) -> U
where U: BitStore {
self.as_bitslice().load_be()
}
fn store_le<U>(&mut self, value: U)
where U: BitStore {
self.as_mut_bitslice().store_le(value)
}
fn store_be<U>(&mut self, value: U)
where U: BitStore {
self.as_mut_bitslice().store_be(value)
}
}
#[inline]
fn mask_for<T>(len: usize) -> T
where T: BitStore {
let len = len as u8;
if len >= T::BITS {
T::TRUE
}
else {
!(T::TRUE << len)
}
}
fn resize<T, U>(value: T) -> U
where T: BitStore, U: BitStore {
let mut out = U::FALSE;
let bytes_t = mem::size_of::<T>();
let bytes_u = mem::size_of::<U>();
unsafe {
if cfg!(target_endian = "big") {
if bytes_t > bytes_u {
ptr::copy_nonoverlapping(
(&value as *const T as *const u8).add(bytes_t - bytes_u),
&mut out as *mut U as *mut u8,
bytes_u,
);
}
else {
ptr::copy_nonoverlapping(
&value as *const T as *const u8,
(&mut out as *mut U as *mut u8).add(bytes_u - bytes_t),
bytes_t,
);
}
}
else {
ptr::copy_nonoverlapping(
&value as *const T as *const u8,
&mut out as *mut U as *mut u8,
cmp::min(bytes_t, bytes_u),
);
}
}
out
}
#[allow(clippy::inconsistent_digit_grouping)]
#[cfg(test)]
mod tests {
use super::*;
use crate::prelude::*;
#[test]
fn lsb0() {
let mut bytes = [0u8; 16];
let bytes = bytes.bits_mut::<Lsb0>();
bytes[1 ..][.. 4].store_le(0x0Au8);
assert_eq!(bytes[1 ..][.. 4].load_le::<u8>(), 0x0Au8);
assert_eq!(bytes.as_slice()[0], 0b000_1010_0u8);
bytes[1 ..][.. 4].store_be(0x05u8);
assert_eq!(bytes[1 ..][.. 4].load_be::<u8>(), 0x05u8);
assert_eq!(bytes.as_slice()[0], 0b000_0101_0u8);
bytes[1 ..][.. 4].store_le(0u8);
let u16b = u16::from_ne_bytes(0x1234u16.to_le_bytes());
bytes[5 ..][.. 14].store_le(u16b);
assert_eq!(bytes[5 ..][.. 14].load_le::<u16>(), 0x1234u16);
assert_eq!(
&bytes.as_slice()[.. 3],
&[0b100_00000, 0b010_0011_0, 0b00000_01_0],
);
bytes[5 ..][.. 14].store_be(u16b);
assert_eq!(bytes[5 ..][.. 14].load_be::<u16>(), 0x1234u16);
assert_eq!(
&bytes.as_slice()[.. 3],
&[0b01_0_00000, 0b010_0011_0, 0b00000_100],
);
let mut shorts = [0u16; 8];
let shorts = shorts.bits_mut::<Lsb0>();
shorts[3 ..][.. 12].store_le(0x0123u16);
assert_eq!(shorts[3 ..][.. 12].load_le::<u16>(), 0x0123u16);
assert_eq!(shorts.as_slice()[0], 0b0_0001_0010_0011_000u16);
shorts[3 ..][.. 12].store_be(0x0123u16);
assert_eq!(shorts[3 ..][.. 12].load_be::<u16>(), 0x0123u16);
assert_eq!(shorts.as_slice()[0], 0b0_0001_0010_0011_000u16);
let mut ints = [0u32; 4];
let ints = ints.bits_mut::<Lsb0>();
ints[1 ..][.. 28].store_le(0x0123_4567u32);
assert_eq!(ints[1 ..][.. 28].load_le::<u32>(), 0x0123_4567u32);
assert_eq!(ints.as_slice()[0], 0b000_0001_0010_0011_0100_0101_0110_0111_0u32);
ints[1 ..][.. 28].store_be(0x0123_4567u32);
assert_eq!(ints[1 ..][.. 28].load_be::<u32>(), 0x0123_4567u32);
assert_eq!(ints.as_slice()[0], 0b000_0001_0010_0011_0100_0101_0110_0111_0u32);
}
#[test]
fn msb0() {
let mut bytes = [0u8; 16];
let bytes = bytes.bits_mut::<Msb0>();
bytes[1 ..][.. 4].store_le(0x0Au8);
assert_eq!(bytes[1 ..][.. 4].load_le::<u8>(), 0x0Au8);
assert_eq!(bytes.as_slice()[0], 0b0_1010_000u8);
bytes[1 ..][.. 4].store_be(0x05u8);
assert_eq!(bytes[1 ..][.. 4].load_be::<u8>(), 0x05u8);
assert_eq!(bytes.as_slice()[0], 0b0_0101_000u8);
bytes[1 ..][.. 4].store_le(0u8);
let u16b = u16::from_ne_bytes(0x1234u16.to_le_bytes());
bytes[5 ..][.. 14].store_le(u16b);
assert_eq!(bytes[5 ..][.. 14].load_le::<u16>(), 0x1234u16);
assert_eq!(
&bytes.as_slice()[.. 3],
&[0b00000_100, 0b010_0011_0, 0b01_0_00000],
);
bytes[5 ..][.. 14].store_be(u16b);
assert_eq!(bytes[5 ..][.. 14].load_be::<u16>(), 0x1234u16);
assert_eq!(
&bytes.as_slice()[.. 3],
&[0b00000_01_0, 0b010_0011_0, 0b100_00000],
);
let mut shorts = [0u16; 8];
let shorts = shorts.bits_mut::<Msb0>();
shorts[3 ..][.. 12].store_le(0x0123u16);
assert_eq!(shorts[3 ..][.. 12].load_le::<u16>(), 0x0123u16);
assert_eq!(shorts.as_slice()[0], 0b000_0001_0010_0011_0u16);
shorts[3 ..][.. 12].store_be(0x0123u16);
assert_eq!(shorts[3 ..][.. 12].load_be::<u16>(), 0x0123u16);
assert_eq!(shorts.as_slice()[0], 0b000_0001_0010_0011_0u16);
let mut ints = [0u32; 4];
let ints = ints.bits_mut::<Msb0>();
ints[1 ..][.. 28].store_le(0x0123_4567u32);
assert_eq!(ints[1 ..][.. 28].load_le::<u32>(), 0x0123_4567u32);
assert_eq!(ints.as_slice()[0], 0b0_0001_0010_0011_0100_0101_0110_0111_000u32);
ints[1 ..][.. 28].store_be(0x0123_4567u32);
assert_eq!(ints[1 ..][.. 28].load_be::<u32>(), 0x0123_4567u32);
assert_eq!(ints.as_slice()[0], 0b0_0001_0010_0011_0100_0101_0110_0111_000u32);
}
}
#[cfg(test)]
mod permutation_tests;