use crate::analysis::cpa::lattice::JoinSemiLattice;
use std::cmp::Ordering;
use std::fmt::{Debug, Display, Formatter, LowerHex};
use std::hash::Hash;
#[derive(PartialEq, Eq, Copy, Clone, Hash, Debug)]
pub enum FlatLattice<C> {
Value(C),
Top,
}
impl<C> From<C> for FlatLattice<C> {
fn from(value: C) -> Self {
FlatLattice::Value(value)
}
}
impl<C> From<FlatLattice<C>> for Option<C> {
fn from(value: FlatLattice<C>) -> Self {
match value {
FlatLattice::Top => None,
FlatLattice::Value(a) => Some(a),
}
}
}
impl<T: PartialEq<T>> PartialEq<T> for FlatLattice<T> {
fn eq(&self, other: &T) -> bool {
match self {
FlatLattice::Value(t) => t == other,
FlatLattice::Top => false,
}
}
}
impl<C: Display> Display for FlatLattice<C> {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
match self {
FlatLattice::Value(a) => f
.debug_tuple("FlatLattice")
.field(&format_args!("{a}"))
.finish(),
FlatLattice::Top => write!(f, "FlatLattice(Top)"),
}
}
}
impl<C: LowerHex> LowerHex for FlatLattice<C> {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
match self {
FlatLattice::Value(a) => f
.debug_tuple("FlatLattice")
.field(&format_args!("{a:x}"))
.finish(),
FlatLattice::Top => write!(f, "FlatLattice(Top)"),
}
}
}
impl<C: PartialOrd + PartialEq + Clone> FlatLattice<C> {
pub fn is_top(&self) -> bool {
matches!(self, FlatLattice::Top)
}
pub fn value(&self) -> Option<&C> {
match self {
FlatLattice::Value(c) => Some(c),
FlatLattice::Top => None,
}
}
}
impl<C: PartialOrd + PartialEq + Clone> PartialOrd for FlatLattice<C> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
match (&self, &other) {
(Self::Top, Self::Top) => Some(Ordering::Equal),
(Self::Top, Self::Value(_)) => Some(Ordering::Greater),
(Self::Value(_), Self::Top) => Some(Ordering::Less),
(Self::Value(a), Self::Value(b)) => {
if a == b {
Some(Ordering::Equal)
} else {
None
}
}
}
}
}
impl<C: PartialOrd + Eq + Clone> JoinSemiLattice for FlatLattice<C> {
fn join(&mut self, other: &Self) {
match (&self, other) {
(Self::Top, _) => *self = Self::Top,
(_, Self::Top) => *self = Self::Top,
(Self::Value(a), Self::Value(b)) => {
if a == b {
} else {
*self = Self::Top
}
}
};
}
}
#[cfg(test)]
mod tests {
use crate::analysis::cpa::lattice::flat::FlatLattice;
#[test]
pub fn test_flat_lattice() {
let val1 = FlatLattice::Value(4u64);
let val2 = FlatLattice::Value(5u64);
let top = FlatLattice::Top;
assert_eq!(val1, val1);
assert_eq!(val2, val2);
assert_eq!(top, top);
assert_ne!(val1, val2);
assert_ne!(val1, top);
assert!(top > val1);
assert!(top > val2);
assert!(val1.partial_cmp(&val2).is_none());
assert!(val2.partial_cmp(&val1).is_none());
}
}