use core::{
fmt,
hash::{Hash, Hasher},
num::NonZeroUsize,
ops::Range,
ptr::{self, NonNull},
};
use awint_internals::*;
use const_fn::const_fn;
#[repr(C)]
pub struct Bits {
_custom_dst: CustomDst<Digit>,
}
unsafe impl Send for Bits {}
unsafe impl Sync for Bits {}
impl<'a> Bits {
#[doc(hidden)]
#[inline]
#[const_fn(cfg(feature = "const_support"))]
#[must_use]
pub const unsafe fn from_raw_parts(raw_bits: RawBits) -> &'a Self {
let custom_dst =
CustomDst::<Digit>::from_raw_parts(raw_bits.as_non_null_ptr(), raw_bits.bw());
unsafe { &*(custom_dst as *const Bits) }
}
#[doc(hidden)]
#[inline]
#[const_fn(cfg(feature = "const_support"))]
#[must_use]
pub const unsafe fn from_raw_parts_mut(raw_bits: RawBits) -> &'a mut Self {
let custom_dst =
CustomDst::<Digit>::from_raw_parts(raw_bits.as_non_null_ptr(), raw_bits.bw());
unsafe { &mut *(custom_dst as *mut Bits) }
}
#[doc(hidden)]
#[inline]
#[must_use]
pub const fn const_as_ref(&'a self) -> &'a Bits {
self
}
#[doc(hidden)]
#[inline]
#[const_fn(cfg(feature = "const_support"))]
#[must_use]
pub const fn const_as_mut(&'a mut self) -> &'a mut Bits {
self
}
#[doc(hidden)]
#[inline]
#[must_use]
pub const fn as_ptr(&self) -> *const Digit {
self._custom_dst.as_ptr()
}
#[doc(hidden)]
#[inline]
#[const_fn(cfg(feature = "const_support"))]
#[must_use]
pub const fn as_mut_ptr(&mut self) -> *mut Digit {
self._custom_dst.as_mut_ptr()
}
#[inline]
#[const_fn(cfg(feature = "const_support"))]
#[must_use]
pub const fn nzbw(&self) -> NonZeroUsize {
unsafe { NonZeroUsize::new_unchecked(self._custom_dst.get_usize()) }
}
#[inline]
#[const_fn(cfg(feature = "const_support"))]
#[must_use]
pub const fn bw(&self) -> usize {
self.nzbw().get()
}
#[doc(hidden)]
#[inline]
#[const_fn(cfg(feature = "const_support"))]
#[must_use]
pub const unsafe fn get_unchecked(&self, i: usize) -> Digit {
debug_assert!(i < self.total_digits());
unsafe { *self.as_ptr().add(i) }
}
#[doc(hidden)]
#[inline]
#[const_fn(cfg(feature = "const_support"))]
#[must_use]
pub const unsafe fn get_unchecked_mut(&'a mut self, i: usize) -> &'a mut Digit {
debug_assert!(i < self.total_digits());
unsafe { &mut *self.as_mut_ptr().add(i) }
}
#[doc(hidden)]
#[inline]
#[const_fn(cfg(feature = "const_support"))]
#[must_use]
pub const fn total_digits(&self) -> usize {
total_digits(self.nzbw()).get()
}
#[doc(hidden)]
#[inline]
#[const_fn(cfg(feature = "const_support"))]
#[must_use]
pub const fn unused(&self) -> usize {
if self.extra() == 0 {
0
} else {
BITS - self.extra()
}
}
#[doc(hidden)]
#[inline]
#[const_fn(cfg(feature = "const_support"))]
#[must_use]
pub const fn extra(&self) -> usize {
extra(self.nzbw())
}
#[doc(hidden)]
#[inline]
#[const_fn(cfg(feature = "const_support"))]
#[must_use]
pub const fn first(&self) -> Digit {
unsafe { self.get_unchecked(0) }
}
#[doc(hidden)]
#[inline]
#[const_fn(cfg(feature = "const_support"))]
#[must_use]
pub const fn first_mut(&'a mut self) -> &'a mut Digit {
unsafe { self.get_unchecked_mut(0) }
}
#[doc(hidden)]
#[inline]
#[const_fn(cfg(feature = "const_support"))]
#[must_use]
pub const fn last(&self) -> Digit {
unsafe { self.get_unchecked(self.total_digits() - 1) }
}
#[doc(hidden)]
#[inline]
#[const_fn(cfg(feature = "const_support"))]
#[must_use]
pub const fn last_mut(&'a mut self) -> &'a mut Digit {
unsafe { self.get_unchecked_mut(self.total_digits() - 1) }
}
#[doc(hidden)]
#[inline]
#[const_fn(cfg(feature = "const_support"))]
pub const fn clear_unused_bits(&mut self) {
if self.extra() == 0 {
return }
*self.last_mut() &= MAX >> (BITS - self.extra());
}
#[doc(hidden)]
#[track_caller]
#[const_fn(cfg(feature = "const_support"))]
pub const fn assert_cleared_unused_bits(&self) {
let one: Digit = 1;
if (self.extra() != 0) && (self.last() >= one.wrapping_shl(self.extra() as u32)) {
panic!(
"unused bits are set in a `Bits` struct, they have been set with one of the \
hidden functions and not properly unset with `Bits::clear_unused_bits`"
);
}
}
#[doc(hidden)]
#[inline]
#[const_fn(cfg(feature = "const_support"))]
#[must_use]
pub const unsafe fn internal_subdigits_mut(
this: &'a mut Self,
range_start: usize,
range_end: usize,
) -> &'a mut Self {
unsafe {
let new_start: *mut Digit = this.as_mut_ptr().add(range_start);
let new_nzbw =
NonZeroUsize::new_unchecked(range_end.wrapping_sub(range_start).wrapping_mul(BITS));
Bits::from_raw_parts_mut(RawBits::from_raw_parts(
NonNull::new_unchecked(new_start),
new_nzbw,
))
}
}
#[doc(hidden)]
#[inline]
#[const_fn(cfg(feature = "const_support"))]
#[must_use]
pub const fn as_slice(&'a self) -> &'a [Digit] {
unsafe { &*ptr::slice_from_raw_parts(self.as_ptr(), self.total_digits()) }
}
#[doc(hidden)]
#[inline]
#[const_fn(cfg(feature = "const_support"))]
#[must_use]
pub const fn as_mut_slice(&'a mut self) -> &'a mut [Digit] {
unsafe { &mut *ptr::slice_from_raw_parts_mut(self.as_mut_ptr(), self.total_digits()) }
}
#[doc(hidden)]
#[const_fn(cfg(feature = "const_support"))]
#[must_use]
pub const fn as_bytes_full_width_nonportable(&'a self) -> &'a [u8] {
let size_in_u8 = self.total_digits() * DIGIT_BYTES;
unsafe { &*ptr::slice_from_raw_parts(self.as_ptr() as *const u8, size_in_u8) }
}
#[doc(hidden)]
#[const_fn(cfg(feature = "const_support"))]
#[must_use]
#[inline(always)] pub const fn as_mut_bytes_full_width_nonportable(&'a mut self) -> &'a mut [u8] {
let size_in_u8 = self.total_digits() * DIGIT_BYTES;
unsafe { &mut *ptr::slice_from_raw_parts_mut(self.as_mut_ptr() as *mut u8, size_in_u8) }
}
#[const_fn(cfg(feature = "const_support"))]
pub const fn u8_slice_(&'a mut self, buf: &[u8]) {
let self_byte_width = self.total_digits() * DIGIT_BYTES;
let min_width = if self_byte_width < buf.len() {
self_byte_width
} else {
buf.len()
};
let start = min_width / DIGIT_BYTES;
unsafe {
self.digit_set(false, start..self.total_digits(), false);
ptr::copy_nonoverlapping(
buf.as_ptr(),
self.as_mut_bytes_full_width_nonportable().as_mut_ptr(),
min_width,
);
let cap = if start >= self.total_digits() {
self.total_digits()
} else {
start + 1
};
const_for!(i in {0..cap} {
*self.get_unchecked_mut(i) = Digit::from_le(self.get_unchecked(i));
});
}
self.clear_unused_bits();
}
#[const_fn(cfg(feature = "const_support"))]
pub const fn to_u8_slice(&'a self, buf: &mut [u8]) {
let self_byte_width = self.total_digits() * DIGIT_BYTES;
let min_width = if self_byte_width < buf.len() {
self_byte_width
} else {
buf.len()
};
#[cfg(target_endian = "little")]
{
unsafe {
ptr::copy_nonoverlapping(
self.as_bytes_full_width_nonportable().as_ptr(),
buf.as_mut_ptr(),
min_width,
);
}
}
#[cfg(target_endian = "big")]
{
const_for!(i in {0..self.total_digits()} {
let x = self.as_slice()[i];
let start = i * DIGIT_BYTES;
let end = if (start + DIGIT_BYTES) > buf.len() {
buf.len()
} else {
start + DIGIT_BYTES
};
let mut s = 0;
const_for!(j in {start..end} {
buf[j] = (x >> s) as u8;
s += 8;
});
});
}
unsafe {
ptr::write_bytes(buf.as_mut_ptr().add(min_width), 0, buf.len() - min_width);
}
}
#[doc(hidden)]
#[inline]
#[const_fn(cfg(feature = "const_support"))]
pub const unsafe fn digit_set(
&mut self,
val: bool,
range: Range<usize>,
clear_unused_bits: bool,
) {
debug_assert!(range.end <= self.total_digits());
debug_assert!(range.start <= range.end);
let digit = if val { MAX } else { 0 };
unsafe_for_each_mut!(
self,
x,
{ range.start..range.end }
{ *x = digit },
clear_unused_bits
);
}
#[doc(hidden)]
#[const_fn(cfg(feature = "const_support"))]
#[must_use]
pub const fn get_digit(&self, start: usize) -> Digit {
let digits = digits_u(start);
let bits = extra_u(start);
let mut tmp = 0;
unsafe {
if digits < self.total_digits() {
tmp = self.get_unchecked(digits) >> bits;
if bits != 0 && ((digits + 1) < self.total_digits()) {
tmp |= self.get_unchecked(digits + 1) << (BITS - bits);
}
}
tmp
}
}
#[doc(hidden)]
#[const_fn(cfg(feature = "const_support"))]
#[must_use]
pub const fn get_double_digit(&self, start: usize) -> (Digit, Digit) {
let digits = digits_u(start);
let bits = extra_u(start);
let mut first = 0;
let mut second = 0;
unsafe {
if digits < self.total_digits() {
first = self.get_unchecked(digits) >> bits;
if (digits + 1) < self.total_digits() {
let mid = self.get_unchecked(digits + 1);
if bits == 0 {
second = mid;
} else {
first |= mid << (BITS - bits);
second = mid >> bits;
if (digits + 2) < self.total_digits() {
second |= self.get_unchecked(digits + 2) << (BITS - bits);
}
};
}
}
(first, second)
}
}
}
impl fmt::Debug for Bits {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::LowerHex::fmt(self, f)
}
}
impl fmt::Display for Bits {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(self, f)
}
}
impl fmt::LowerHex for Bits {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.debug_format_hexadecimal(f, false)
}
}
impl fmt::UpperHex for Bits {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.debug_format_hexadecimal(f, true)
}
}
impl fmt::Octal for Bits {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.debug_format_octal(f)
}
}
impl fmt::Binary for Bits {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.debug_format_binary(f)
}
}
impl fmt::Pointer for Bits {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let ptr = self.as_ptr();
fmt::Pointer::fmt(&ptr, f)
}
}
impl Hash for Bits {
fn hash<H: Hasher>(&self, state: &mut H) {
self.bw().hash(state);
self.as_slice().hash(state);
}
}
#[cfg(feature = "zeroize_support")]
impl zeroize::Zeroize for Bits {
fn zeroize(&mut self) {
self.as_mut_slice().zeroize()
}
}