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 awint_internals::*;
use const_fn::const_fn;
#[inline]
pub(crate) const fn layout(bw: NonZeroUsize) -> Layout {
unsafe {
Layout::from_size_align_unchecked(
(regular_digits(bw) + 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"))]
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"))]
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"))]
pub const fn nzbw(&self) -> NonZeroUsize {
self.const_as_ref().nzbw()
}
#[inline]
#[const_fn(cfg(feature = "const_support"))]
pub const fn bw(&self) -> usize {
self.const_as_ref().bw()
}
#[inline]
#[const_fn(cfg(feature = "const_support"))]
pub const fn len(&self) -> usize {
self.const_as_ref().len()
}
#[doc(hidden)]
#[inline]
#[const_fn(cfg(feature = "const_support"))]
pub const fn raw_len(&self) -> usize {
self.const_as_ref().raw_len()
}
#[doc(hidden)]
#[inline]
#[const_fn(cfg(feature = "const_support"))]
pub fn as_ptr(&self) -> *const usize {
self.const_as_ref().as_ptr()
}
#[doc(hidden)]
#[inline]
#[const_fn(cfg(feature = "const_support"))]
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"))]
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_assign(bits).unwrap();
tmp
}
pub fn zero(bw: NonZeroUsize) -> Self {
unsafe {
let ptr: *mut usize = alloc_zeroed(layout(bw)).cast();
ptr.add(regular_digits(bw)).write(bw.get());
ExtAwi::from_raw_parts(ptr, regular_digits(bw) + 1)
}
}
pub fn umax(bw: NonZeroUsize) -> Self {
let mut x = unsafe {
let ptr: *mut usize = alloc(layout(bw)).cast();
ptr.write_bytes(u8::MAX, regular_digits(bw));
ptr.add(regular_digits(bw)).write(bw.get());
ExtAwi::from_raw_parts(ptr, regular_digits(bw) + 1)
};
x.const_as_mut().clear_unused_bits();
x
}
pub fn imax(bw: NonZeroUsize) -> Self {
let mut awi = Self::umax(bw);
*awi.const_as_mut().last_mut() = (isize::MAX as usize) >> awi.const_as_ref().unused();
awi
}
pub fn imin(bw: NonZeroUsize) -> Self {
let mut awi = Self::zero(bw);
*awi.const_as_mut().last_mut() = (isize::MIN as usize) >> awi.const_as_ref().unused();
awi
}
pub fn uone(bw: NonZeroUsize) -> Self {
let mut awi = Self::zero(bw);
*awi.const_as_mut().first_mut() = 1;
awi
}
#[doc(hidden)]
pub fn panicking_zero(bw: usize) -> Self {
Self::zero(NonZeroUsize::new(bw).unwrap())
}
#[doc(hidden)]
pub fn panicking_umax(bw: usize) -> Self {
Self::umax(NonZeroUsize::new(bw).unwrap())
}
#[doc(hidden)]
pub fn panicking_imax(bw: usize) -> Self {
Self::imax(NonZeroUsize::new(bw).unwrap())
}
#[doc(hidden)]
pub fn panicking_imin(bw: usize) -> Self {
Self::imin(NonZeroUsize::new(bw).unwrap())
}
#[doc(hidden)]
pub fn panicking_uone(bw: usize) -> Self {
Self::uone(NonZeroUsize::new(bw).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 {}
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_assign(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_assign(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_assign;
u16 from_u16 u16_assign;
u32 from_u32 u32_assign;
u64 from_u64 u64_assign;
u128 from_u128 u128_assign;
usize from_usize usize_assign;
i8 from_i8 i8_assign;
i16 from_i16 i16_assign;
i32 from_i32 i32_assign;
i64 from_i64 i64_assign;
i128 from_i128 i128_assign;
isize from_isize isize_assign;
);
pub fn from_bool(x: bool) -> Self {
let mut tmp = ExtAwi::zero(bw(1));
tmp.const_as_mut().bool_assign(x);
tmp
}
}
impl From<bool> for ExtAwi {
fn from(x: bool) -> ExtAwi {
let mut tmp = ExtAwi::zero(bw(1));
tmp.const_as_mut().bool_assign(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_assign;
u16, u16_assign;
u32, u32_assign;
u64, u64_assign;
u128, u128_assign;
usize, usize_assign;
i8, i8_assign;
i16, i16_assign;
i32, i32_assign;
i64, i64_assign;
i128, i128_assign;
isize, isize_assign;
);