lattices/
conflict.rs
1use std::cmp::Ordering::{self, *};
2
3use crate::{DeepReveal, IsBot, IsTop, LatticeFrom, LatticeOrd, Merge};
4
5#[repr(transparent)]
15#[derive(Copy, Clone, Debug, Eq)]
16#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
17pub struct Conflict<T>(Option<T>);
18impl<T> Conflict<T> {
19 pub fn new(val: Option<T>) -> Self {
21 Self(val)
22 }
23
24 pub fn new_from(val: impl Into<Option<T>>) -> Self {
26 Self::new(val.into())
27 }
28
29 pub fn as_reveal_ref(&self) -> Option<&T> {
31 self.0.as_ref()
32 }
33
34 pub fn as_reveal_mut(&mut self) -> Option<&mut T> {
36 self.0.as_mut()
37 }
38
39 pub fn into_reveal(self) -> Option<T> {
41 self.0
42 }
43}
44
45impl<T> DeepReveal for Conflict<T> {
46 type Revealed = Option<T>;
47
48 fn deep_reveal(self) -> Self::Revealed {
49 self.0
50 }
51}
52
53impl<T, O> Merge<Conflict<O>> for Conflict<T>
54where
55 T: PartialEq<O>,
56{
57 fn merge(&mut self, other: Conflict<O>) -> bool {
58 if let Some(val_self) = &self.0 {
59 if other.0.is_none_or(|val_other| val_self != &val_other) {
60 self.0 = None;
61 return true;
62 }
63 }
64 false
65 }
66}
67
68impl<T> LatticeFrom<Conflict<T>> for Conflict<T> {
69 fn lattice_from(other: Conflict<T>) -> Self {
70 other
71 }
72}
73
74impl<T, O> PartialOrd<Conflict<O>> for Conflict<T>
75where
76 T: PartialEq<O>,
77{
78 fn partial_cmp(&self, other: &Conflict<O>) -> Option<Ordering> {
79 match (&self.0, &other.0) {
80 (None, None) => Some(Equal),
81 (None, Some(_)) => Some(Greater),
82 (Some(_), None) => Some(Less),
83 (Some(val_self), Some(val_other)) => (val_self == val_other).then_some(Equal),
84 }
85 }
86}
87impl<T, O> LatticeOrd<Conflict<O>> for Conflict<T> where Self: PartialOrd<Conflict<O>> {}
88
89impl<T, O> PartialEq<Conflict<O>> for Conflict<T>
90where
91 T: PartialEq<O>,
92{
93 fn eq(&self, other: &Conflict<O>) -> bool {
94 match (&self.0, &other.0) {
95 (None, None) => true,
96 (Some(val_self), Some(val_other)) => val_self == val_other,
97 _ => false,
98 }
99 }
100}
101
102impl<T> IsBot for Conflict<T> {
103 fn is_bot(&self) -> bool {
104 false
105 }
106}
107
108impl<T> IsTop for Conflict<T> {
109 fn is_top(&self) -> bool {
110 self.0.is_none()
111 }
112}
113
114#[cfg(test)]
115mod test {
116 use super::*;
117 use crate::WithBot;
118 use crate::test::{
119 check_all, check_lattice_is_bot, check_lattice_is_top, check_lattice_ord,
120 check_lattice_properties, check_partial_ord_properties,
121 };
122
123 #[test]
124 fn consistency() {
125 let items = &[
126 Conflict::new_from("foo"),
127 Conflict::new_from("bar"),
128 Conflict::new(None),
129 ];
130 check_lattice_ord(items);
131 check_partial_ord_properties(items);
132 check_lattice_properties(items);
133 check_lattice_is_bot(items);
134 check_lattice_is_top(items);
135 }
136
137 #[test]
138 fn consistency_withbot() {
139 let items = &[
140 WithBot::new_from(Conflict::new_from("foo")),
141 WithBot::new_from(Conflict::new_from("bar")),
142 WithBot::new_from(Conflict::new(None)),
143 WithBot::new(None),
144 ];
145 check_all(items);
146 }
147}