use core::fmt;
use core::ops::Not;
pub type Var = u32;
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Lit(u32);
impl Lit {
#[inline]
pub const fn new(var: Var, sign: bool) -> Lit {
Lit((var << 1) | sign as u32)
}
#[inline]
pub const fn pos(var: Var) -> Lit {
Lit::new(var, false)
}
#[inline]
pub const fn neg(var: Var) -> Lit {
Lit::new(var, true)
}
#[inline]
pub const fn var(self) -> Var {
self.0 >> 1
}
#[inline]
pub const fn sign(self) -> bool {
(self.0 & 1) == 1
}
#[inline]
pub const fn index(self) -> u32 {
self.0
}
#[inline]
pub const fn from_index(i: u32) -> Lit {
Lit(i)
}
}
impl Not for Lit {
type Output = Lit;
#[inline]
fn not(self) -> Lit {
Lit(self.0 ^ 1)
}
}
impl fmt::Display for Lit {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.sign() {
write!(f, "-{}", self.var())
} else {
write!(f, "{}", self.var())
}
}
}
impl fmt::Debug for Lit {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Lit({self})")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn packing_and_negation() {
let p = Lit::pos(3);
let n = Lit::neg(3);
assert_eq!(p.var(), 3);
assert!(!p.sign());
assert!(n.sign());
assert_eq!(!p, n);
assert_eq!(!n, p);
assert_eq!(!!p, p);
assert_eq!(Lit::from_index(p.index()), p);
assert_eq!(p.index(), 6);
assert_eq!(n.index(), 7);
}
#[test]
fn display() {
use alloc::format;
assert_eq!(format!("{}", Lit::pos(2)), "2");
assert_eq!(format!("{}", Lit::neg(2)), "-2");
}
}