nonempty_containers/ne_set.rs
1//! A non-empty set type that guarantees at least one element is present. [NESet] has an
2//! interface similar to [HashSet] with additional methods to enforce the invariant. Get started
3//! with:
4//!
5//! ```rust, no_run
6//! # use nonempty_containers::{nes, NESet};
7//! #
8//! let nes = NESet::new(42, vec![1, 2, 3]);
9//! let singleton = NESet::singleton(42);
10//! let r#macro = nes![1, 2, 3];
11//! ```
12//!
13//! [NESet] conforms to [Index], [IntoIterator], [Deref], and many more, so operations are
14//! as [HashSet]-like as possible. They are also usually zero-cost.
15//!
16//! ```rust, no_run
17//! # use nonempty_containers::{nes, NESet};
18//! #
19//! let nes = nes![42, 1, 2, 3];
20//! assert!(nes.contains(&42));
21//! assert_eq!(nes.len(), 4);
22//! ```
23//!
24//! When the feature `arbitrary` is enabled, [NESet] implements [arbitrary::Arbitrary]
25//! for generation of randomly populated instances.
26
27use crate::errors::NonEmptyError;
28use std::collections::hash_set::{IntoIter, Iter};
29use std::collections::HashSet;
30use std::hash::Hash;
31
32/// Non-empty set type.
33#[derive(Debug, Eq, PartialEq, Clone)]
34pub struct NESet<T: Eq + Hash>(HashSet<T>);
35
36impl<T: Eq + Hash> NESet<T> {
37 /// Creates a new [NESet], ensuring at least one element is present.
38 pub fn new(head: T, tail: Vec<T>) -> Self {
39 let mut set = HashSet::with_capacity(1 + tail.len());
40 set.insert(head);
41 set.extend(tail);
42 Self(set)
43 }
44
45 /// Creates a new singleton [NESet]. Semantically equivalent to:
46 /// ```no_run
47 /// # use nonempty_containers::NESet;
48 /// # let value = 42;
49 /// #
50 /// NESet::new(value, Vec::new());
51 /// ```
52 pub fn singleton(value: T) -> Self {
53 let mut set = HashSet::new();
54 set.insert(value);
55 Self(set)
56 }
57
58 /// Creates a new [NESet] from a [HashSet]. Returns an error if the set is empty.
59 pub fn from(set: HashSet<T>) -> Result<Self, NonEmptyError> {
60 match set.is_empty() {
61 true => Err(NonEmptyError::Empty),
62 false => Ok(Self(set)),
63 }
64 }
65
66 /// Creates a new [NESet] from a [HashSet] without checking the invariant. This is unsafe
67 /// and should only be used by macros in this crate.
68 #[doc(hidden)]
69 pub fn __from_set_unsafe(set: HashSet<T>) -> Self {
70 debug_assert!(!set.is_empty());
71 Self(set)
72 }
73
74 /// Extracts the underlying [HashSet]. This operation is zero-cost.
75 pub fn into_set(self) -> HashSet<T> {
76 self.0
77 }
78
79 /// Returns the size of the set.
80 pub fn len(&self) -> usize {
81 self.0.len()
82 }
83
84 /// A [NESet] is always non-empty.
85 pub fn is_empty(&self) -> bool {
86 false
87 }
88
89 /// Adds an element to the set. If the element is already present, it is not modified.
90 pub fn insert(&mut self, value: T) -> bool {
91 self.0.insert(value)
92 }
93
94 /// Removes an element from the set. Returns `true` if the element was present.
95 pub fn remove(&mut self, value: &T) -> bool {
96 self.0.remove(value)
97 }
98
99 /// Checks if the set contains a value.
100 pub fn contains(&self, value: &T) -> bool {
101 self.0.contains(value)
102 }
103}
104
105impl<T: Eq + Hash> From<NESet<T>> for HashSet<T> {
106 fn from(value: NESet<T>) -> Self {
107 value.into_set()
108 }
109}
110
111impl<T: Eq + Hash> TryFrom<HashSet<T>> for NESet<T> {
112 type Error = NonEmptyError;
113
114 fn try_from(set: HashSet<T>) -> Result<Self, Self::Error> {
115 NESet::from(set)
116 }
117}
118
119impl<T: Eq + Hash> From<T> for NESet<T> {
120 fn from(value: T) -> Self {
121 Self::singleton(value)
122 }
123}
124
125impl<'a, T: Eq + Hash> IntoIterator for &'a NESet<T> {
126 type Item = &'a T;
127 type IntoIter = Iter<'a, T>;
128
129 fn into_iter(self) -> Self::IntoIter {
130 self.0.iter()
131 }
132}
133
134impl<T: Eq + Hash> IntoIterator for NESet<T> {
135 type Item = T;
136 type IntoIter = IntoIter<T>;
137
138 fn into_iter(self) -> Self::IntoIter {
139 self.0.into_iter()
140 }
141}