1#[cfg(feature = "alloc")]
4use alloc::collections::BTreeSet;
5use core::cmp::Ordering::{self, *};
6use core::marker::PhantomData;
7#[cfg(feature = "std")]
8use std::collections::HashSet;
9
10use cc_traits::SimpleCollectionRef;
11
12#[cfg(feature = "alloc")]
13use crate::Atomize;
14use crate::cc_traits::{Iter, Len, Set};
15use crate::collections::{ArraySet, OptionSet, SingletonSet};
16use crate::{DeepReveal, IsBot, IsTop, LatticeBimorphism, LatticeFrom, LatticeOrd, Merge};
17
18#[repr(transparent)]
22#[derive(Copy, Clone, Debug, Default)]
23#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
24pub struct SetUnion<Set>(pub Set);
25impl<Set> SetUnion<Set> {
26 pub fn new(val: Set) -> Self {
28 Self(val)
29 }
30
31 pub fn new_from(val: impl Into<Set>) -> Self {
33 Self::new(val.into())
34 }
35
36 pub fn as_reveal_ref(&self) -> &Set {
38 &self.0
39 }
40
41 pub fn as_reveal_mut(&mut self) -> &mut Set {
43 &mut self.0
44 }
45
46 pub fn into_reveal(self) -> Set {
48 self.0
49 }
50}
51
52impl<Set> DeepReveal for SetUnion<Set> {
53 type Revealed = Set;
54
55 fn deep_reveal(self) -> Self::Revealed {
56 self.0
57 }
58}
59
60impl<SetSelf, SetOther, Item> Merge<SetUnion<SetOther>> for SetUnion<SetSelf>
61where
62 SetSelf: Extend<Item> + Len,
63 SetOther: IntoIterator<Item = Item>,
64{
65 fn merge(&mut self, other: SetUnion<SetOther>) -> bool {
66 let old_len = self.0.len();
67 self.0.extend(other.0);
68 self.0.len() > old_len
69 }
70}
71
72impl<SetSelf, SetOther, Item> LatticeFrom<SetUnion<SetOther>> for SetUnion<SetSelf>
73where
74 SetSelf: FromIterator<Item>,
75 SetOther: IntoIterator<Item = Item>,
76{
77 fn lattice_from(other: SetUnion<SetOther>) -> Self {
78 Self(other.0.into_iter().collect())
79 }
80}
81
82impl<SetSelf, SetOther, Item> PartialOrd<SetUnion<SetOther>> for SetUnion<SetSelf>
83where
84 SetSelf: Set<Item, Item = Item> + Iter,
85 SetOther: Set<Item, Item = Item> + Iter,
86{
87 fn partial_cmp(&self, other: &SetUnion<SetOther>) -> Option<Ordering> {
88 match self.0.len().cmp(&other.0.len()) {
89 Greater => {
90 if other.0.iter().all(|key| self.0.contains(&*key)) {
91 Some(Greater)
92 } else {
93 None
94 }
95 }
96 Equal => {
97 if self.0.iter().all(|key| other.0.contains(&*key)) {
98 Some(Equal)
99 } else {
100 None
101 }
102 }
103 Less => {
104 if self.0.iter().all(|key| other.0.contains(&*key)) {
105 Some(Less)
106 } else {
107 None
108 }
109 }
110 }
111 }
112}
113impl<SetSelf, SetOther> LatticeOrd<SetUnion<SetOther>> for SetUnion<SetSelf> where
114 Self: PartialOrd<SetUnion<SetOther>>
115{
116}
117
118impl<SetSelf, SetOther, Item> PartialEq<SetUnion<SetOther>> for SetUnion<SetSelf>
119where
120 SetSelf: Set<Item, Item = Item> + Iter,
121 SetOther: Set<Item, Item = Item> + Iter,
122{
123 fn eq(&self, other: &SetUnion<SetOther>) -> bool {
124 if self.0.len() != other.0.len() {
125 return false;
126 }
127
128 self.0.iter().all(|key| other.0.contains(&*key))
129 }
130}
131impl<SetSelf> Eq for SetUnion<SetSelf> where Self: PartialEq {}
132
133impl<Set> IsBot for SetUnion<Set>
134where
135 Set: Len,
136{
137 fn is_bot(&self) -> bool {
138 self.0.is_empty()
139 }
140}
141
142impl<Set> IsTop for SetUnion<Set> {
143 fn is_top(&self) -> bool {
144 false
145 }
146}
147
148#[cfg(feature = "alloc")]
149impl<Set, Item> Atomize for SetUnion<Set>
150where
151 Set: Len + IntoIterator<Item = Item> + Extend<Item>,
152 Set::IntoIter: 'static,
153 Item: 'static,
154{
155 type Atom = SetUnionSingletonSet<Item>;
156
157 type AtomIter = alloc::boxed::Box<dyn Iterator<Item = Self::Atom>>;
159
160 fn atomize(self) -> Self::AtomIter {
161 alloc::boxed::Box::new(self.0.into_iter().map(SetUnionSingletonSet::new_from))
162 }
163}
164
165#[cfg(feature = "std")]
167pub type SetUnionHashSet<Item> = SetUnion<HashSet<Item>>;
168
169#[cfg(feature = "alloc")]
171pub type SetUnionBTreeSet<Item> = SetUnion<BTreeSet<Item>>;
172
173#[cfg(feature = "alloc")]
175pub type SetUnionVec<Item> = SetUnion<alloc::vec::Vec<Item>>;
176
177pub type SetUnionArray<Item, const N: usize> = SetUnion<ArraySet<Item, N>>;
179
180pub type SetUnionSingletonSet<Item> = SetUnion<SingletonSet<Item>>;
182
183pub type SetUnionOptionSet<Item> = SetUnion<OptionSet<Item>>;
185
186pub struct CartesianProductBimorphism<SetOut> {
189 _phantom: PhantomData<fn() -> SetOut>,
190}
191impl<SetOut> Default for CartesianProductBimorphism<SetOut> {
192 fn default() -> Self {
193 Self {
194 _phantom: Default::default(),
195 }
196 }
197}
198impl<SetA, SetB, SetOut> LatticeBimorphism<SetUnion<SetA>, SetUnion<SetB>>
199 for CartesianProductBimorphism<SetOut>
200where
201 SetA: IntoIterator,
202 SetB: Iter + SimpleCollectionRef,
203 SetA::Item: Clone,
204 SetB::Item: Clone,
205 SetOut: FromIterator<(SetA::Item, SetB::Item)>,
206{
207 type Output = SetUnion<SetOut>;
208
209 fn call(&mut self, lat_a: SetUnion<SetA>, lat_b: SetUnion<SetB>) -> Self::Output {
210 let set_a = lat_a.into_reveal();
211 let set_b = lat_b.into_reveal();
212 let set_out = set_a
213 .into_iter()
214 .flat_map(|a_item| {
215 set_b
216 .iter()
217 .map(<SetB as SimpleCollectionRef>::into_ref)
218 .cloned()
219 .map(move |b_item| (a_item.clone(), b_item))
220 })
221 .collect::<SetOut>();
222 SetUnion::new(set_out)
223 }
224}
225
226#[cfg(test)]
227mod test {
228 use super::*;
229 use crate::test::{check_all, check_atomize_each, check_lattice_bimorphism};
230
231 #[test]
232 fn test_set_union() {
233 let mut my_set_a = SetUnionHashSet::<&str>::new(HashSet::new());
234 let my_set_b = SetUnionBTreeSet::<&str>::new(BTreeSet::new());
235 let my_set_c = SetUnionSingletonSet::new(SingletonSet("hello world"));
236
237 assert_eq!(Some(Equal), my_set_a.partial_cmp(&my_set_a));
238 assert_eq!(Some(Equal), my_set_a.partial_cmp(&my_set_b));
239 assert_eq!(Some(Less), my_set_a.partial_cmp(&my_set_c));
240 assert_eq!(Some(Equal), my_set_b.partial_cmp(&my_set_a));
241 assert_eq!(Some(Equal), my_set_b.partial_cmp(&my_set_b));
242 assert_eq!(Some(Less), my_set_b.partial_cmp(&my_set_c));
243 assert_eq!(Some(Greater), my_set_c.partial_cmp(&my_set_a));
244 assert_eq!(Some(Greater), my_set_c.partial_cmp(&my_set_b));
245 assert_eq!(Some(Equal), my_set_c.partial_cmp(&my_set_c));
246
247 assert!(!my_set_a.merge(my_set_b));
248 assert!(my_set_a.merge(my_set_c));
249 }
250
251 #[test]
252 fn test_singleton_example() {
253 let mut my_hash_set = SetUnionHashSet::<&str>::default();
254 let my_delta_set = SetUnionSingletonSet::new_from("hello world");
255 let my_array_set = SetUnionArray::new_from(["hello world", "b", "c", "d"]);
256
257 assert_eq!(Some(Equal), my_delta_set.partial_cmp(&my_delta_set));
258 assert_eq!(Some(Less), my_delta_set.partial_cmp(&my_array_set));
259 assert_eq!(Some(Greater), my_array_set.partial_cmp(&my_delta_set));
260 assert_eq!(Some(Equal), my_array_set.partial_cmp(&my_array_set));
261
262 assert!(my_hash_set.merge(my_array_set)); assert!(!my_hash_set.merge(my_delta_set)); }
265
266 #[test]
267 fn consistency() {
268 check_all(&[
269 SetUnionHashSet::new_from([]),
270 SetUnionHashSet::new_from([0]),
271 SetUnionHashSet::new_from([1]),
272 SetUnionHashSet::new_from([0, 1]),
273 ]);
274 }
275
276 #[test]
277 fn atomize() {
278 check_atomize_each(&[
279 SetUnionHashSet::new_from([]),
280 SetUnionHashSet::new_from([0]),
281 SetUnionHashSet::new_from([1]),
282 SetUnionHashSet::new_from([0, 1]),
283 SetUnionHashSet::new((0..10).collect()),
284 ]);
285 }
286
287 #[test]
288 fn cartesian_product() {
289 let items_a = &[
290 SetUnionHashSet::new_from([]),
291 SetUnionHashSet::new_from([0]),
292 SetUnionHashSet::new_from([1]),
293 SetUnionHashSet::new_from([0, 1]),
294 ];
295 let items_b = &[
296 SetUnionBTreeSet::new("hello".chars().collect()),
297 SetUnionBTreeSet::new("world".chars().collect()),
298 ];
299
300 check_lattice_bimorphism(
301 CartesianProductBimorphism::<HashSet<_>>::default(),
302 items_a,
303 items_a,
304 );
305 check_lattice_bimorphism(
306 CartesianProductBimorphism::<HashSet<_>>::default(),
307 items_a,
308 items_b,
309 );
310 check_lattice_bimorphism(
311 CartesianProductBimorphism::<HashSet<_>>::default(),
312 items_b,
313 items_a,
314 );
315 check_lattice_bimorphism(
316 CartesianProductBimorphism::<HashSet<_>>::default(),
317 items_b,
318 items_b,
319 );
320 }
321}