lattices/
point.rs

1use std::marker::PhantomData;
2
3use crate::{DeepReveal, IsBot, IsTop, LatticeFrom, LatticeOrd, Merge};
4
5/// A `Point` lattice, corresponding to a single instance of `T`.
6///
7/// Will runtime panic if a merge between inequal values is attempted.
8///
9/// The `Provenance` generic param is a token for the origin of this point. The parameter can be
10/// used to differentiate between points with different provenances. This will prevent them from
11/// being merged together, avoiding any posibility of panic.
12///
13/// Like [`Conflict<T>`](crate::Conflict) but will panic instead of going to a "conflict" top
14/// state.
15///
16/// Can be thought of as a lattice with a domain of size one, corresponding to the specific value
17/// inside.
18///
19/// This also can be used to wrap non lattice data into a lattice in a way that typechecks.
20#[repr(transparent)]
21#[derive(Copy, Clone, Debug, Default, Eq)]
22#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
23pub struct Point<T, Provenance> {
24    /// The value stored inside. This should not be mutated.
25    pub val: T,
26    _token: PhantomData<*mut Provenance>,
27}
28impl<T, Provenance> Point<T, Provenance> {
29    /// Create a new `Point` lattice instance from a value.
30    pub fn new(val: T) -> Self {
31        Self {
32            val,
33            _token: PhantomData,
34        }
35    }
36
37    /// Create a new `Point` lattice instance from a value using `Into`.
38    pub fn new_from(val: impl Into<T>) -> Self {
39        Self::new(val.into())
40    }
41}
42impl<T, Provenance> DeepReveal for Point<T, Provenance> {
43    type Revealed = T;
44
45    fn deep_reveal(self) -> Self::Revealed {
46        self.val
47    }
48}
49
50impl<T, Provenance> Merge<Point<T, Provenance>> for Point<T, Provenance>
51where
52    T: PartialEq,
53{
54    fn merge(&mut self, other: Point<T, Provenance>) -> bool {
55        if self.val != other.val {
56            panic!("The `Point` lattice cannot merge inequal elements.")
57        }
58        false
59    }
60}
61
62impl<T, Provenance> LatticeFrom<Point<T, Provenance>> for Point<T, Provenance> {
63    fn lattice_from(other: Point<T, Provenance>) -> Self {
64        other
65    }
66}
67
68impl<T, Provenance> PartialOrd<Point<T, Provenance>> for Point<T, Provenance>
69where
70    T: PartialEq,
71{
72    fn partial_cmp(&self, other: &Point<T, Provenance>) -> Option<std::cmp::Ordering> {
73        if self.val != other.val {
74            panic!("The `Point` lattice does not have a partial order between inequal elements.");
75        }
76        Some(std::cmp::Ordering::Equal)
77    }
78}
79impl<T, Provenance> LatticeOrd<Point<T, Provenance>> for Point<T, Provenance> where
80    Self: PartialOrd<Point<T, Provenance>>
81{
82}
83
84impl<T, Provenance> PartialEq<Point<T, Provenance>> for Point<T, Provenance>
85where
86    T: PartialEq,
87{
88    fn eq(&self, other: &Point<T, Provenance>) -> bool {
89        self.val == other.val
90    }
91}
92
93impl<T, Provenance> IsBot for Point<T, Provenance> {
94    fn is_bot(&self) -> bool {
95        true
96    }
97}
98
99impl<T, Provenance> IsTop for Point<T, Provenance> {
100    fn is_top(&self) -> bool {
101        true
102    }
103}
104
105#[cfg(test)]
106mod test {
107    use super::*;
108    use crate::test::{
109        check_all, check_lattice_ord, check_lattice_properties, check_partial_ord_properties,
110    };
111
112    #[test]
113    fn consistency_equal() {
114        check_all(&[Point::<_, ()>::new("hello world")])
115    }
116
117    #[test]
118    fn consistency_inequal() {
119        use std::collections::BTreeSet;
120
121        let items: &[Point<_, ()>] = &[
122            Point::new(BTreeSet::from_iter([])),
123            Point::new(BTreeSet::from_iter([0])),
124            Point::new(BTreeSet::from_iter([1])),
125            Point::new(BTreeSet::from_iter([0, 1])),
126        ];
127
128        // Merged inequal elements panic, therefore `NaiveMerge` panics.
129        assert!(std::panic::catch_unwind(|| check_lattice_ord(items)).is_err());
130        // `Point` does not have a partial order.
131        assert!(std::panic::catch_unwind(|| check_partial_ord_properties(items)).is_err());
132        // `Point` is not actually a lattice.
133        assert!(std::panic::catch_unwind(|| check_lattice_properties(items)).is_err());
134    }
135}