use byteorder::LE;
use mm0_util::SortId;
use zerocopy::{AsBytes, FromBytes, Unaligned, U64};
pub const TYPE_BOUND_MASK: u64 = 1 << 63;
pub const TYPE_SORT_MASK: u64 = (1 << 63) | ((1 << 56) - 1);
pub const TYPE_DEPS_MASK: u64 = (1 << 56) - 1;
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, FromBytes, AsBytes, Unaligned)]
pub struct Type(U64<LE>);
pub type Arg = Type;
impl std::default::Default for Type {
fn default() -> Self { Type(U64::new(0)) }
}
impl From<u64> for Type {
fn from(n: u64) -> Type { Type(U64::new(n)) }
}
impl Type {
#[must_use]
pub fn into_inner(self) -> u64 { self.0.get() }
#[must_use]
pub fn new_of_sort(sort_num: u8) -> Self { Type::from(u64::from(sort_num) << 56) }
#[must_use]
pub fn new(bound: bool) -> Self {
if bound {
Type::from(1 << 63)
} else {
Type::from(0)
}
}
pub fn add_sort(&mut self, sort_id: SortId) {
*self &= Type::from(TYPE_SORT_MASK);
*self |= Type::from(u64::from(sort_id.into_inner()) << 56)
}
pub fn add_dep(&mut self, bv_idx: u64) { *self |= Type::from(1 << bv_idx) }
#[must_use]
pub fn depends_on(self, bv_idx: u64) -> bool { self.0.get() & (1 << bv_idx) != 0 }
#[inline]
#[must_use]
pub fn bound(self) -> bool { self.0.get() & (1 << 63) != 0 }
#[allow(clippy::cast_possible_truncation)]
#[inline]
#[must_use]
pub fn sort(self) -> SortId { SortId(((self.0.get() >> 56) & 0x7F) as u8) }
#[inline]
#[must_use]
pub fn bound_digit(self) -> Option<u64> {
if self.bound() {
Some(self.0.get() & !(0xFF << 56))
} else {
None
}
}
#[must_use]
pub fn bound_pos(self) -> Option<u64> {
if self.bound() {
for i in 0..56 {
if ((1 << i) & self.0.get()) != 0 {
return Some(i + 1)
}
}
unreachable!("Something's wrong with `is_bound`")
} else {
None
}
}
#[inline]
#[must_use]
pub fn has_deps(self) -> bool {
if self.bound() {
false
} else {
(self.0.get() & TYPE_DEPS_MASK) > 0
}
}
#[inline]
#[must_use]
pub fn deps(self) -> Option<u64> {
if self.bound() {
None
} else {
Some(self.deps_unchecked())
}
}
#[inline]
#[must_use]
pub fn deps_unchecked(self) -> u64 { self.0.get() & !(0xFF << 56) }
#[must_use]
pub fn high_bit(self) -> Self { Type(U64::new(self.0.get() & !TYPE_DEPS_MASK)) }
#[must_use]
pub fn disjoint(self, other: Self) -> bool { (self.0.get() & other.0.get()) == 0 }
}
impl std::ops::BitAnd<Type> for Type {
type Output = Self;
fn bitand(self, rhs: Self) -> Self::Output { Type::from(self.0.get() & rhs.0.get()) }
}
impl std::ops::BitAndAssign<Type> for Type {
fn bitand_assign(&mut self, other: Self) { self.0.set(self.0.get() & other.0.get()) }
}
impl std::ops::BitOr<Type> for Type {
type Output = Self;
fn bitor(self, rhs: Self) -> Self::Output { Type::from(self.0.get() | rhs.0.get()) }
}
impl std::ops::BitOrAssign<Type> for Type {
fn bitor_assign(&mut self, other: Self) { self.0.set(self.0.get() | other.0.get()) }
}
impl std::ops::Not for Type {
type Output = Type;
fn not(self) -> Self::Output { Type::from(!self.0.get()) }
}