Skip to main content

lattices/
point.rs

1use core::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        assert!(
56            self.val == other.val,
57            "The `Point` lattice cannot merge inequal elements."
58        );
59        false
60    }
61}
62
63impl<T, Provenance> LatticeFrom<Point<T, Provenance>> for Point<T, Provenance> {
64    fn lattice_from(other: Point<T, Provenance>) -> Self {
65        other
66    }
67}
68
69impl<T, Provenance> PartialOrd<Point<T, Provenance>> for Point<T, Provenance>
70where
71    T: PartialEq,
72{
73    fn partial_cmp(&self, other: &Point<T, Provenance>) -> Option<core::cmp::Ordering> {
74        assert!(
75            self.val == other.val,
76            "The `Point` lattice does not have a partial order between inequal elements."
77        );
78        Some(core::cmp::Ordering::Equal)
79    }
80}
81impl<T, Provenance> LatticeOrd<Point<T, Provenance>> for Point<T, Provenance> where
82    Self: PartialOrd<Point<T, Provenance>>
83{
84}
85
86impl<T, Provenance> PartialEq<Point<T, Provenance>> for Point<T, Provenance>
87where
88    T: PartialEq,
89{
90    fn eq(&self, other: &Point<T, Provenance>) -> bool {
91        self.val == other.val
92    }
93}
94
95impl<T, Provenance> IsBot for Point<T, Provenance> {
96    fn is_bot(&self) -> bool {
97        true
98    }
99}
100
101impl<T, Provenance> IsTop for Point<T, Provenance> {
102    fn is_top(&self) -> bool {
103        true
104    }
105}
106
107#[cfg(test)]
108mod test {
109    use super::*;
110    use crate::test::{
111        check_all, check_lattice_ord, check_lattice_properties, check_partial_ord_properties,
112    };
113
114    #[test]
115    fn consistency_equal() {
116        check_all(&[Point::<_, ()>::new("hello world")])
117    }
118
119    #[test]
120    fn consistency_inequal() {
121        use std::collections::BTreeSet;
122
123        let items: &[Point<_, ()>] = &[
124            Point::new(BTreeSet::from_iter([])),
125            Point::new(BTreeSet::from_iter([0])),
126            Point::new(BTreeSet::from_iter([1])),
127            Point::new(BTreeSet::from_iter([0, 1])),
128        ];
129
130        // Merged inequal elements panic, therefore `NaiveMerge` panics.
131        assert!(std::panic::catch_unwind(|| check_lattice_ord(items)).is_err());
132        // `Point` does not have a partial order.
133        assert!(std::panic::catch_unwind(|| check_partial_ord_properties(items)).is_err());
134        // `Point` is not actually a lattice.
135        assert!(std::panic::catch_unwind(|| check_lattice_properties(items)).is_err());
136    }
137}