use crate::memory::Offset;
use serde::{
de::{self, Visitor},
Deserialize, Deserializer, Serialize, Serializer,
};
use std::{convert::TryFrom, fmt, fmt::Display, ops};
#[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord)]
pub struct Variable(pub u32);
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, PartialOrd, Ord, Default)]
pub struct Literal {
pub encoding: u32,
}
impl Variable {
pub fn new(value: u32) -> Variable {
Variable(value)
}
pub fn literal(self) -> Literal {
requires!(i32::try_from(self.0).is_ok());
Literal::new(self.0 as i32)
}
pub fn array_size_for_variables(self) -> usize {
self.as_offset() + 1
}
pub fn array_size_for_literals(self) -> usize {
2 * (self.as_offset() + 1)
}
}
impl Offset for Variable {
fn as_offset(&self) -> usize {
requires!(usize::try_from(self.0).is_ok());
self.0 as usize
}
}
impl Display for Variable {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.literal())
}
}
impl Literal {
pub fn new(value: i32) -> Literal {
requires!(value != i32::min_value());
requires!((value.abs() as u32) < u32::pow(2, 31));
Literal {
encoding: (value.abs() as u32) * 2 + ((value < 0) as u32),
}
}
pub const fn from_raw(encoding: u32) -> Literal {
Literal { encoding }
}
pub const TOP: Literal = Literal { encoding: 0 };
pub const BOTTOM: Literal = Literal { encoding: 1 };
pub const NEVER_READ: Literal = Literal {
encoding: u32::max_value(),
};
pub fn decode(self) -> i32 {
let magnitude = self.variable().0 as i32;
if self.encoding & 1 != 0 {
-magnitude
} else {
magnitude
}
}
pub const fn variable(self) -> Variable {
Variable(self.encoding / 2)
}
pub fn is_constant(self) -> bool {
self.encoding <= 1
}
pub fn all(maxvar: Variable) -> impl Iterator<Item = Literal> {
let first = Variable(1).literal().encoding;
let last = maxvar.literal().encoding;
(first..last + 2).map(Literal::from_raw)
}
pub const fn is_zero(self) -> bool {
self.encoding == 0
}
}
impl Offset for Literal {
fn as_offset(&self) -> usize {
self.encoding as usize
}
}
impl ops::Neg for Literal {
type Output = Literal;
fn neg(self) -> Literal {
Literal {
encoding: self.encoding ^ 1,
}
}
}
impl Display for Literal {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{}{}",
if self == &Literal::TOP {
"+"
} else if self == &Literal::BOTTOM {
"-"
} else {
""
},
self.decode()
)
}
}
impl Serialize for Literal {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
requires!(
!self.is_constant(),
"serialization of boolean constants is not supported"
);
serializer.serialize_i32(self.decode())
}
}
impl<'de> Deserialize<'de> for Literal {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let result = Literal::new(deserializer.deserialize_i32(I32Visitor)?);
requires!(
!result.is_constant(),
"deserialization of boolean constants is not supported"
);
Ok(result)
}
}
struct I32Visitor;
impl<'de> Visitor<'de> for I32Visitor {
type Value = i32;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("an integer between -2^31 and 2^31")
}
fn visit_i8<E>(self, value: i8) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(i32::from(value))
}
fn visit_i32<E>(self, value: i32) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(value)
}
fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
where
E: de::Error,
{
use std::i32;
if value >= i64::from(i32::MIN) && value <= i64::from(i32::MAX) {
Ok(value as i32)
} else {
Err(E::custom(format!("i32 out of range: {}", value)))
}
}
}