jsonld_core/object/node/
multiset.rs1use std::hash::{BuildHasher, Hash};
2
3#[derive(Debug, Default, Clone, Copy)]
4pub struct DeterministicHasherBuilder;
7
8impl BuildHasher for DeterministicHasherBuilder {
9 type Hasher = foldhash::fast::FoldHasher<'static>;
10
11 fn build_hasher(&self) -> Self::Hasher {
12 foldhash::fast::FixedState::default().build_hasher()
13 }
14}
15
16use jsonld_syntax::IntoJsonWithContext;
17
18#[derive(Debug, Clone)]
20pub struct Multiset<T, S = DeterministicHasherBuilder> {
21 data: Vec<T>,
22 hasher: S,
23}
24
25impl<T, S: Default> Default for Multiset<T, S> {
26 fn default() -> Self {
27 Self {
28 data: Vec::new(),
29 hasher: S::default(),
30 }
31 }
32}
33
34impl<T, S> Multiset<T, S> {
35 #[must_use]
37 pub fn new() -> Self
38 where
39 S: Default,
40 {
41 Self::default()
42 }
43
44 #[must_use]
46 pub fn with_capacity(cap: usize) -> Self
47 where
48 S: Default,
49 {
50 Self {
51 data: Vec::with_capacity(cap),
52 hasher: S::default(),
53 }
54 }
55
56 pub fn len(&self) -> usize {
58 self.data.len()
59 }
60
61 pub fn is_empty(&self) -> bool {
63 self.data.is_empty()
64 }
65
66 pub fn contains(&self, value: &T) -> bool
68 where
69 T: PartialEq,
70 {
71 self.data.contains(value)
72 }
73
74 pub fn iter(&self) -> core::slice::Iter<'_, T> {
77 self.data.iter()
78 }
79
80 pub fn iter_mut(&mut self) -> core::slice::IterMut<'_, T> {
83 self.data.iter_mut()
84 }
85
86 pub fn as_slice(&self) -> &[T] {
88 &self.data
89 }
90}
91
92impl<T: Hash, S: BuildHasher> Multiset<T, S> {
93 pub fn singleton(value: T) -> Self
95 where
96 S: Default,
97 {
98 let mut result = Self::new();
99 result.insert(value);
100 result
101 }
102
103 pub fn insert(&mut self, value: T) {
106 self.data.push(value);
107 }
108
109 pub fn insert_unique(&mut self, value: T) -> bool
112 where
113 T: PartialEq,
114 {
115 if self.contains(&value) {
116 false
117 } else {
118 self.insert(value);
119 true
120 }
121 }
122}
123
124impl<'a, T, S> IntoIterator for &'a Multiset<T, S> {
125 type Item = &'a T;
126 type IntoIter = core::slice::Iter<'a, T>;
127
128 fn into_iter(self) -> Self::IntoIter {
129 self.iter()
130 }
131}
132
133impl<'a, T, S> IntoIterator for &'a mut Multiset<T, S> {
134 type Item = &'a mut T;
135 type IntoIter = core::slice::IterMut<'a, T>;
136
137 fn into_iter(self) -> Self::IntoIter {
138 self.iter_mut()
139 }
140}
141
142impl<T, S> IntoIterator for Multiset<T, S> {
143 type Item = T;
144 type IntoIter = std::vec::IntoIter<T>;
145
146 fn into_iter(self) -> Self::IntoIter {
147 self.data.into_iter()
148 }
149}
150
151impl<T: Hash, S: Default + BuildHasher> FromIterator<T> for Multiset<T, S> {
152 fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
153 let mut result = Self::new();
154
155 for item in iter {
156 result.insert(item);
157 }
158
159 result
160 }
161}
162
163impl<T: Hash, S: BuildHasher> Extend<T> for Multiset<T, S> {
164 fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
165 for item in iter {
166 self.insert(item);
167 }
168 }
169}
170
171impl<T: PartialEq<U>, U, S, P> PartialEq<Multiset<U, P>> for Multiset<T, S> {
172 fn eq(&self, other: &Multiset<U, P>) -> bool {
173 compare_unordered(&self.data, &other.data)
174 }
175}
176
177pub(crate) fn compare_unordered<T: PartialEq<U>, U>(a: &[T], b: &[U]) -> bool {
178 if a.len() == b.len() {
179 let mut free_indexes = Vec::new();
180 free_indexes.resize(a.len(), true);
181
182 for item in a {
183 match free_indexes.iter_mut().enumerate().find(|(i, free)| **free && item == &b[*i]) {
184 Some((_, free)) => *free = false,
185 None => return false,
186 }
187 }
188
189 true
190 } else {
191 false
192 }
193}
194
195pub(crate) fn compare_unordered_opt<T: PartialEq<U>, U>(a: Option<&[T]>, b: Option<&[U]>) -> bool {
196 match (a, b) {
197 (Some(a), Some(b)) => compare_unordered(a, b),
198 (None, None) => true,
199 _ => false,
200 }
201}
202
203impl<T: Eq, S> Eq for Multiset<T, S> {}
204
205impl<T: Hash, S: BuildHasher> Hash for Multiset<T, S> {
206 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
207 let mut hash = 0u64;
208
209 for item in self {
210 hash = hash.wrapping_add(self.hasher.hash_one(item));
211 }
212
213 state.write_u64(hash);
214 }
215}
216
217impl<T: IntoJsonWithContext<N>, S, N> IntoJsonWithContext<N> for Multiset<T, S> {
218 fn into_json_with(self, vocabulary: &N) -> jstrict::Value {
219 jstrict::Value::Array(self.into_iter().map(|item| item.into_json_with(vocabulary)).collect())
220 }
221}