#[allow(dead_code)]
pub trait Lattice: Clone + Eq + Sized {
fn bot() -> Self;
fn join(&self, other: &Self) -> Self;
fn leq(&self, other: &Self) -> bool;
}
#[allow(dead_code)]
pub trait AbstractDomain: Lattice {
fn top() -> Self;
fn meet(&self, other: &Self) -> Self;
fn widen(&self, other: &Self) -> Self;
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Clone, Debug, PartialEq, Eq)]
struct Three(u8);
impl Lattice for Three {
fn bot() -> Self {
Three(0)
}
fn join(&self, other: &Self) -> Self {
Three(self.0.max(other.0))
}
fn leq(&self, other: &Self) -> bool {
self.0 <= other.0
}
}
#[test]
fn bot_identity() {
let a = Three(1);
assert_eq!(a.join(&Three::bot()), a);
assert_eq!(Three::bot().join(&a), a);
}
#[test]
fn join_commutative() {
let a = Three(1);
let b = Three(2);
assert_eq!(a.join(&b), b.join(&a));
}
#[test]
fn join_associative() {
let a = Three(0);
let b = Three(1);
let c = Three(2);
assert_eq!(a.join(&b).join(&c), a.join(&b.join(&c)));
}
#[test]
fn join_idempotent() {
let a = Three(1);
assert_eq!(a.join(&a), a);
}
#[test]
fn leq_reflexive() {
let a = Three(1);
assert!(a.leq(&a));
}
#[test]
fn leq_transitive() {
let a = Three(0);
let b = Three(1);
let c = Three(2);
assert!(a.leq(&b));
assert!(b.leq(&c));
assert!(a.leq(&c));
}
#[test]
fn leq_consistent_with_join() {
let a = Three(1);
let b = Three(2);
assert!(a.leq(&b));
assert_eq!(a.join(&b), b);
}
}