1use std::marker::PhantomData;
23use crate::{DeepReveal, IsBot, IsTop, LatticeFrom, LatticeOrd, Merge};
45/// 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.
25pub val: T,
26 _token: PhantomData<*mut Provenance>,
27}
28impl<T, Provenance> Point<T, Provenance> {
29/// Create a new `Point` lattice instance from a value.
30pub fn new(val: T) -> Self {
31Self {
32 val,
33 _token: PhantomData,
34 }
35 }
3637/// Create a new `Point` lattice instance from a value using `Into`.
38pub fn new_from(val: impl Into<T>) -> Self {
39Self::new(val.into())
40 }
41}
42impl<T, Provenance> DeepReveal for Point<T, Provenance> {
43type Revealed = T;
4445fn deep_reveal(self) -> Self::Revealed {
46self.val
47 }
48}
4950impl<T, Provenance> Merge<Point<T, Provenance>> for Point<T, Provenance>
51where
52T: PartialEq,
53{
54fn merge(&mut self, other: Point<T, Provenance>) -> bool {
55if self.val != other.val {
56panic!("The `Point` lattice cannot merge inequal elements.")
57 }
58false
59}
60}
6162impl<T, Provenance> LatticeFrom<Point<T, Provenance>> for Point<T, Provenance> {
63fn lattice_from(other: Point<T, Provenance>) -> Self {
64 other
65 }
66}
6768impl<T, Provenance> PartialOrd<Point<T, Provenance>> for Point<T, Provenance>
69where
70T: PartialEq,
71{
72fn partial_cmp(&self, other: &Point<T, Provenance>) -> Option<std::cmp::Ordering> {
73if self.val != other.val {
74panic!("The `Point` lattice does not have a partial order between inequal elements.");
75 }
76Some(std::cmp::Ordering::Equal)
77 }
78}
79impl<T, Provenance> LatticeOrd<Point<T, Provenance>> for Point<T, Provenance> where
80Self: PartialOrd<Point<T, Provenance>>
81{
82}
8384impl<T, Provenance> PartialEq<Point<T, Provenance>> for Point<T, Provenance>
85where
86T: PartialEq,
87{
88fn eq(&self, other: &Point<T, Provenance>) -> bool {
89self.val == other.val
90 }
91}
9293impl<T, Provenance> IsBot for Point<T, Provenance> {
94fn is_bot(&self) -> bool {
95true
96}
97}
9899impl<T, Provenance> IsTop for Point<T, Provenance> {
100fn is_top(&self) -> bool {
101true
102}
103}
104105#[cfg(test)]
106mod test {
107use super::*;
108use crate::test::{
109 check_all, check_lattice_ord, check_lattice_properties, check_partial_ord_properties,
110 };
111112#[test]
113fn consistency_equal() {
114 check_all(&[Point::<_, ()>::new("hello world")])
115 }
116117#[test]
118fn consistency_inequal() {
119use std::collections::BTreeSet;
120121let 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 ];
127128// Merged inequal elements panic, therefore `NaiveMerge` panics.
129assert!(std::panic::catch_unwind(|| check_lattice_ord(items)).is_err());
130// `Point` does not have a partial order.
131assert!(std::panic::catch_unwind(|| check_partial_ord_properties(items)).is_err());
132// `Point` is not actually a lattice.
133assert!(std::panic::catch_unwind(|| check_lattice_properties(items)).is_err());
134 }
135}