Skip to main content

use_set/
lib.rs

1#![forbid(unsafe_code)]
2#![doc = include_str!("../README.md")]
3
4//! Set utilities for `RustUse`.
5
6/// Returns whether `value` is a member of `set`.
7#[must_use]
8pub fn contains_member<T>(set: &[T], value: &T) -> bool
9where
10    T: PartialEq,
11{
12    set.contains(value)
13}
14
15/// Returns whether every unique value in `left` appears in `right`.
16#[must_use]
17pub fn is_subset<T>(left: &[T], right: &[T]) -> bool
18where
19    T: PartialEq,
20{
21    left.iter().all(|value| right.contains(value))
22}
23
24/// Returns whether `left` and `right` share no common members.
25#[must_use]
26pub fn are_disjoint<T>(left: &[T], right: &[T]) -> bool
27where
28    T: PartialEq,
29{
30    left.iter().all(|value| !right.contains(value))
31}
32
33/// Returns the unique members of `left ∪ right` in first-seen order.
34#[must_use]
35pub fn set_union<T>(left: &[T], right: &[T]) -> Vec<T>
36where
37    T: Clone + PartialEq,
38{
39    let mut values = Vec::new();
40
41    append_unique(&mut values, left);
42    append_unique(&mut values, right);
43
44    values
45}
46
47/// Returns the unique members of `left ∩ right` in the order they first appear in `left`.
48#[must_use]
49pub fn set_intersection<T>(left: &[T], right: &[T]) -> Vec<T>
50where
51    T: Clone + PartialEq,
52{
53    let mut values = Vec::new();
54
55    for value in left {
56        if right.contains(value) {
57            push_unique(&mut values, value);
58        }
59    }
60
61    values
62}
63
64/// Returns the unique members of `left \ right` in the order they first appear in `left`.
65#[must_use]
66pub fn set_difference<T>(left: &[T], right: &[T]) -> Vec<T>
67where
68    T: Clone + PartialEq,
69{
70    let mut values = Vec::new();
71
72    for value in left {
73        if !right.contains(value) {
74            push_unique(&mut values, value);
75        }
76    }
77
78    values
79}
80
81/// Returns the unique members that appear in exactly one of `left` or `right`.
82#[must_use]
83pub fn set_symmetric_difference<T>(left: &[T], right: &[T]) -> Vec<T>
84where
85    T: Clone + PartialEq,
86{
87    let mut values = set_difference(left, right);
88
89    for value in right {
90        if !left.contains(value) {
91            push_unique(&mut values, value);
92        }
93    }
94
95    values
96}
97
98fn append_unique<T>(target: &mut Vec<T>, source: &[T])
99where
100    T: Clone + PartialEq,
101{
102    for value in source {
103        push_unique(target, value);
104    }
105}
106
107fn push_unique<T>(target: &mut Vec<T>, value: &T)
108where
109    T: Clone + PartialEq,
110{
111    if !target.contains(value) {
112        target.push(value.clone());
113    }
114}
115
116pub mod prelude;
117
118#[cfg(test)]
119mod tests {
120    use super::{
121        are_disjoint, contains_member, is_subset, set_difference, set_intersection,
122        set_symmetric_difference, set_union,
123    };
124
125    #[test]
126    fn evaluates_membership_and_relations() {
127        let left = [1, 2, 2, 3];
128        let right = [2, 3, 4];
129        let subset = [2, 2, 3];
130
131        assert!(contains_member(&left, &2));
132        assert!(!contains_member(&left, &5));
133        assert!(is_subset(&subset, &right));
134        assert!(!is_subset(&left, &right));
135        assert!(are_disjoint(&[7, 8], &right));
136        assert!(!are_disjoint(&left, &right));
137    }
138
139    #[test]
140    fn computes_order_preserving_set_operations() {
141        let left = [1, 2, 2, 3];
142        let right = [3, 4, 2, 5];
143
144        assert_eq!(set_union(&left, &right), vec![1, 2, 3, 4, 5]);
145        assert_eq!(set_intersection(&left, &right), vec![2, 3]);
146        assert_eq!(set_difference(&left, &right), vec![1]);
147        assert_eq!(set_symmetric_difference(&left, &right), vec![1, 4, 5]);
148    }
149}