use alloc::alloc::{alloc, alloc_zeroed, dealloc, Layout};
use core::{
borrow::{Borrow, BorrowMut},
fmt,
hash::{Hash, Hasher},
mem,
num::NonZeroUsize,
ops::{Deref, DerefMut, Index, IndexMut, RangeFull},
ptr,
ptr::NonNull,
};
use awint_core::{Bits, InlAwi};
use const_fn::const_fn;
use crate::awint_internals::*;
#[inline]
pub(crate) const fn layout(w: NonZeroUsize) -> Layout {
unsafe {
Layout::from_size_align_unchecked(
(regular_digits(w) + 1) * mem::size_of::<usize>(),
mem::align_of::<usize>(),
)
}
}
#[repr(transparent)]
pub struct ExtAwi {
raw: NonNull<Bits>,
}
unsafe impl Send for ExtAwi {}
unsafe impl Sync for ExtAwi {}
impl<'a> ExtAwi {
#[doc(hidden)]
#[inline]
#[const_fn(cfg(feature = "const_support"))]
pub const unsafe fn from_raw_parts(ptr: *mut usize, raw_len: usize) -> ExtAwi {
unsafe {
ExtAwi {
raw: NonNull::new_unchecked(Bits::from_raw_parts_mut(ptr, raw_len)),
}
}
}
#[inline]
#[const_fn(cfg(feature = "const_support"))]
#[must_use]
pub const fn const_as_ref(&'a self) -> &'a Bits {
unsafe { mem::transmute::<NonNull<Bits>, &Bits>(self.raw) }
}
#[inline]
#[const_fn(cfg(feature = "const_support"))]
#[must_use]
pub const fn const_as_mut(&'a mut self) -> &'a mut Bits {
unsafe { mem::transmute::<NonNull<Bits>, &mut Bits>(self.raw) }
}
#[inline]
#[const_fn(cfg(feature = "const_support"))]
#[must_use]
pub const fn nzbw(&self) -> NonZeroUsize {
self.const_as_ref().nzbw()
}
#[inline]
#[const_fn(cfg(feature = "const_support"))]
#[must_use]
pub const fn bw(&self) -> usize {
self.const_as_ref().bw()
}
#[inline]
#[const_fn(cfg(feature = "const_support"))]
#[must_use]
pub const fn len(&self) -> usize {
self.const_as_ref().len()
}
#[doc(hidden)]
#[inline]
#[const_fn(cfg(feature = "const_support"))]
#[must_use]
pub const fn raw_len(&self) -> usize {
self.const_as_ref().raw_len()
}
#[doc(hidden)]
#[inline]
#[const_fn(cfg(feature = "const_support"))]
#[must_use]
pub fn as_ptr(&self) -> *const usize {
self.const_as_ref().as_ptr()
}
#[doc(hidden)]
#[inline]
#[const_fn(cfg(feature = "const_support"))]
#[must_use]
pub fn as_mut_ptr(&mut self) -> *mut usize {
self.const_as_mut().as_mut_ptr()
}
#[doc(hidden)]
#[inline]
#[const_fn(cfg(feature = "const_support"))]
#[must_use]
pub const fn layout(&self) -> Layout {
layout(self.nzbw())
}
pub fn from_bits(bits: &Bits) -> ExtAwi {
let mut tmp = ExtAwi::zero(bits.nzbw());
tmp.const_as_mut().copy_(bits).unwrap();
tmp
}
pub fn zero(w: NonZeroUsize) -> Self {
unsafe {
let ptr: *mut usize = alloc_zeroed(layout(w)).cast();
ptr.add(regular_digits(w)).write(w.get());
ExtAwi::from_raw_parts(ptr, regular_digits(w) + 1)
}
}
pub fn umax(w: NonZeroUsize) -> Self {
let mut x = unsafe {
let ptr: *mut usize = alloc(layout(w)).cast();
ptr.write_bytes(u8::MAX, regular_digits(w));
ptr.add(regular_digits(w)).write(w.get());
ExtAwi::from_raw_parts(ptr, regular_digits(w) + 1)
};
x.const_as_mut().clear_unused_bits();
x
}
pub fn imax(w: NonZeroUsize) -> Self {
let mut awi = Self::umax(w);
*awi.const_as_mut().last_mut() = (isize::MAX as usize) >> awi.const_as_ref().unused();
awi
}
pub fn imin(w: NonZeroUsize) -> Self {
let mut awi = Self::zero(w);
*awi.const_as_mut().last_mut() = (isize::MIN as usize) >> awi.const_as_ref().unused();
awi
}
pub fn uone(w: NonZeroUsize) -> Self {
let mut awi = Self::zero(w);
*awi.const_as_mut().first_mut() = 1;
awi
}
#[doc(hidden)]
pub fn panicking_zero(w: usize) -> Self {
Self::zero(NonZeroUsize::new(w).unwrap())
}
#[doc(hidden)]
pub fn panicking_umax(w: usize) -> Self {
Self::umax(NonZeroUsize::new(w).unwrap())
}
#[doc(hidden)]
pub fn panicking_imax(w: usize) -> Self {
Self::imax(NonZeroUsize::new(w).unwrap())
}
#[doc(hidden)]
pub fn panicking_imin(w: usize) -> Self {
Self::imin(NonZeroUsize::new(w).unwrap())
}
#[doc(hidden)]
pub fn panicking_uone(w: usize) -> Self {
Self::uone(NonZeroUsize::new(w).unwrap())
}
}
impl Drop for ExtAwi {
fn drop(&mut self) {
unsafe {
dealloc(self.as_mut_ptr().cast(), self.layout());
}
}
}
impl Clone for ExtAwi {
fn clone(&self) -> ExtAwi {
unsafe {
let dst = alloc(self.layout()).cast();
ptr::copy_nonoverlapping(self.as_ptr(), dst, self.raw_len());
ExtAwi::from_raw_parts(dst, self.raw_len())
}
}
}
impl PartialEq for ExtAwi {
fn eq(&self, rhs: &Self) -> bool {
self.const_as_ref() == rhs.const_as_ref()
}
}
impl Eq for ExtAwi {}
#[cfg(feature = "zeroize_support")]
impl zeroize::Zeroize for ExtAwi {
fn zeroize(&mut self) {
self.as_mut().zeroize()
}
}
macro_rules! impl_fmt {
($($ty:ident)*) => {
$(
impl fmt::$ty for ExtAwi {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::$ty::fmt(self.const_as_ref(), f)
}
}
)*
};
}
impl_fmt!(Debug Display LowerHex UpperHex Octal Binary);
impl Hash for ExtAwi {
fn hash<H: Hasher>(&self, state: &mut H) {
self.const_as_ref().hash(state);
}
}
impl Deref for ExtAwi {
type Target = Bits;
#[inline]
fn deref(&self) -> &Self::Target {
self.const_as_ref()
}
}
impl DerefMut for ExtAwi {
#[inline]
fn deref_mut(&mut self) -> &mut Bits {
self.const_as_mut()
}
}
impl Index<RangeFull> for ExtAwi {
type Output = Bits;
#[inline]
fn index(&self, _i: RangeFull) -> &Bits {
self.const_as_ref()
}
}
impl Borrow<Bits> for ExtAwi {
#[inline]
fn borrow(&self) -> &Bits {
self.const_as_ref()
}
}
impl AsRef<Bits> for ExtAwi {
#[inline]
fn as_ref(&self) -> &Bits {
self.const_as_ref()
}
}
impl IndexMut<RangeFull> for ExtAwi {
#[inline]
fn index_mut(&mut self, _i: RangeFull) -> &mut Bits {
self.const_as_mut()
}
}
impl BorrowMut<Bits> for ExtAwi {
#[inline]
fn borrow_mut(&mut self) -> &mut Bits {
self.const_as_mut()
}
}
impl AsMut<Bits> for ExtAwi {
#[inline]
fn as_mut(&mut self) -> &mut Bits {
self.const_as_mut()
}
}
impl From<&Bits> for ExtAwi {
fn from(bits: &Bits) -> ExtAwi {
let mut tmp = ExtAwi::zero(bits.nzbw());
tmp.const_as_mut().copy_(bits).unwrap();
tmp
}
}
impl<const BW: usize, const LEN: usize> From<InlAwi<BW, LEN>> for ExtAwi {
fn from(awi: InlAwi<BW, LEN>) -> ExtAwi {
let mut tmp = ExtAwi::zero(awi.nzbw());
tmp.const_as_mut().copy_(awi.const_as_ref()).unwrap();
tmp
}
}
macro_rules! extawi_from_ty {
($($ty:ident $from:ident $assign:ident);*;) => {
$(
pub fn $from(x: $ty) -> Self {
let mut tmp = ExtAwi::zero(bw($ty::BITS as usize));
tmp.const_as_mut().$assign(x);
tmp
}
)*
};
}
impl ExtAwi {
extawi_from_ty!(
u8 from_u8 u8_;
u16 from_u16 u16_;
u32 from_u32 u32_;
u64 from_u64 u64_;
u128 from_u128 u128_;
usize from_usize usize_;
i8 from_i8 i8_;
i16 from_i16 i16_;
i32 from_i32 i32_;
i64 from_i64 i64_;
i128 from_i128 i128_;
isize from_isize isize_;
);
pub fn from_bool(x: bool) -> Self {
let mut tmp = ExtAwi::zero(bw(1));
tmp.const_as_mut().bool_(x);
tmp
}
}
impl From<bool> for ExtAwi {
fn from(x: bool) -> ExtAwi {
let mut tmp = ExtAwi::zero(bw(1));
tmp.const_as_mut().bool_(x);
tmp
}
}
macro_rules! extawi_from {
($($ty:ident, $assign:ident);*;) => {
$(
impl From<$ty> for ExtAwi {
fn from(x: $ty) -> Self {
let mut tmp = ExtAwi::zero(bw($ty::BITS as usize));
tmp.const_as_mut().$assign(x);
tmp
}
}
)*
};
}
extawi_from!(
u8, u8_;
u16, u16_;
u32, u32_;
u64, u64_;
u128, u128_;
usize, usize_;
i8, i8_;
i16, i16_;
i32, i32_;
i64, i64_;
i128, i128_;
isize, isize_;
);