use acls_rs::algebra::{BoundedJoinSemilattice, BoundedMeetSemilattice};
use acls_rs::prelude::*;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use std::cmp::Ordering;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[non_exhaustive]
pub enum Scope {
Base,
OneLevel,
Subtree,
}
impl Scope {
fn rank(self) -> u8 {
match self {
Self::Base => 0,
Self::OneLevel => 1,
Self::Subtree => 2,
}
}
}
impl Ord for Scope {
fn cmp(&self, other: &Self) -> Ordering {
self.rank().cmp(&other.rank())
}
}
impl PartialOrd for Scope {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Semigroup for Scope {
fn combine(self, other: Self) -> Self {
self.max(other)
}
}
impl Monoid for Scope {
fn identity() -> Self {
Self::Base
}
}
impl MeetSemilattice for Scope {
fn meet(self, other: Self) -> Self {
self.min(other)
}
}
impl JoinSemilattice for Scope {
fn join(self, other: Self) -> Self {
self.max(other)
}
}
impl BoundedMeetSemilattice for Scope {
fn top() -> Self {
Self::Subtree
}
}
impl BoundedJoinSemilattice for Scope {
fn bottom() -> Self {
Self::Base
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn total_order() {
assert!(Scope::Base < Scope::OneLevel);
assert!(Scope::OneLevel < Scope::Subtree);
assert!(Scope::Base < Scope::Subtree);
}
#[test]
fn reflexive() {
for s in [Scope::Base, Scope::OneLevel, Scope::Subtree] {
assert_eq!(s.partial_cmp(&s), Some(Ordering::Equal));
}
}
#[test]
fn lattice_meet_is_min() {
assert_eq!(Scope::Base.meet(Scope::Subtree), Scope::Base);
assert_eq!(Scope::Subtree.meet(Scope::OneLevel), Scope::OneLevel);
assert_eq!(Scope::OneLevel.meet(Scope::OneLevel), Scope::OneLevel);
}
#[test]
fn lattice_join_is_max() {
assert_eq!(Scope::Base.join(Scope::Subtree), Scope::Subtree);
assert_eq!(Scope::Base.join(Scope::OneLevel), Scope::OneLevel);
assert_eq!(Scope::Subtree.join(Scope::Subtree), Scope::Subtree);
}
#[test]
fn monoid_identity() {
for s in [Scope::Base, Scope::OneLevel, Scope::Subtree] {
assert_eq!(s.combine(Scope::identity()), s);
assert_eq!(Scope::identity().combine(s), s);
}
}
#[test]
fn bounded_top_bottom() {
for s in [Scope::Base, Scope::OneLevel, Scope::Subtree] {
assert_eq!(s.meet(Scope::top()), s);
assert_eq!(s.join(Scope::bottom()), s);
}
}
#[test]
fn absorption() {
for a in [Scope::Base, Scope::OneLevel, Scope::Subtree] {
for b in [Scope::Base, Scope::OneLevel, Scope::Subtree] {
assert_eq!(a.meet(a.join(b)), a);
assert_eq!(a.join(a.meet(b)), a);
}
}
}
}