1use super::{Multiset, Objects};
2use crate::{
3 object::{InvalidExpandedJson, TryFromJson, TryFromJsonObject},
4 Id, IndexedObject,
5};
6use educe::Educe;
7use indexmap::IndexMap;
8use rdf_types::VocabularyMut;
9use std::hash::{Hash, Hasher};
10
11pub type PropertyObjects<T, B> = Multiset<IndexedObject<T, B>>;
12
13#[derive(Educe, Debug, Clone)]
15#[educe(
16 PartialEq(bound = "T: Eq + Hash, B: Eq + Hash"),
17 Eq(bound = "T: Eq + Hash, B: Eq + Hash")
18)]
19pub struct Properties<T, B>(IndexMap<Id<T, B>, PropertyObjects<T, B>>);
20
21impl<T, B> Default for Properties<T, B> {
22 fn default() -> Self {
23 Self::new()
24 }
25}
26
27impl<T, B> Properties<T, B> {
28 pub fn new() -> Self {
30 Self(IndexMap::new())
31 }
32
33 #[inline(always)]
35 pub fn len(&self) -> usize {
36 self.0.len()
37 }
38
39 #[inline(always)]
41 pub fn is_empty(&self) -> bool {
42 self.0.is_empty()
43 }
44
45 #[inline(always)]
47 pub fn iter(&self) -> Iter<'_, T, B> {
48 Iter {
49 inner: self.0.iter(),
50 }
51 }
52
53 #[inline(always)]
55 pub fn iter_mut(&mut self) -> IterMut<'_, T, B> {
56 self.0.iter_mut()
57 }
58
59 #[inline(always)]
61 pub fn clear(&mut self) {
62 self.0.clear()
63 }
64}
65
66impl<T: Eq + Hash, B: Eq + Hash> Properties<T, B> {
67 #[inline(always)]
69 pub fn contains<Q: ?Sized + Hash + indexmap::Equivalent<Id<T, B>>>(&self, prop: &Q) -> bool {
70 self.0.get(prop).is_some()
71 }
72
73 #[inline(always)]
75 pub fn get<Q: ?Sized + Hash + indexmap::Equivalent<Id<T, B>>>(
76 &self,
77 prop: &Q,
78 ) -> Objects<T, B> {
79 match self.0.get(prop) {
80 Some(values) => Objects::new(Some(values.iter())),
81 None => Objects::new(None),
82 }
83 }
84
85 #[inline(always)]
89 pub fn get_any<Q: ?Sized + Hash + indexmap::Equivalent<Id<T, B>>>(
90 &self,
91 prop: &Q,
92 ) -> Option<&IndexedObject<T, B>> {
93 match self.0.get(prop) {
94 Some(values) => values.iter().next(),
95 None => None,
96 }
97 }
98
99 #[inline(always)]
101 pub fn insert(&mut self, prop: Id<T, B>, value: IndexedObject<T, B>) {
102 if let Some(node_values) = self.0.get_mut(&prop) {
103 node_values.insert(value);
104 } else {
105 self.0.insert(prop, Multiset::singleton(value));
106 }
107 }
108
109 #[inline(always)]
111 pub fn insert_unique(&mut self, prop: Id<T, B>, value: IndexedObject<T, B>) {
112 if let Some(node_values) = self.0.get_mut(&prop) {
113 if node_values.iter().all(|v| !v.equivalent(&value)) {
114 node_values.insert(value)
115 }
116 } else {
117 self.0.insert(prop, Multiset::singleton(value));
118 }
119 }
120
121 #[inline(always)]
123 pub fn insert_all<Objects: IntoIterator<Item = IndexedObject<T, B>>>(
124 &mut self,
125 prop: Id<T, B>,
126 values: Objects,
127 ) {
128 if let Some(node_values) = self.0.get_mut(&prop) {
129 node_values.extend(values);
130 } else {
131 self.0.insert(prop, values.into_iter().collect());
132 }
133 }
134
135 #[inline(always)]
139 pub fn insert_all_unique<Objects: IntoIterator<Item = IndexedObject<T, B>>>(
140 &mut self,
141 prop: Id<T, B>,
142 values: Objects,
143 ) {
144 if let Some(node_values) = self.0.get_mut(&prop) {
145 for value in values {
146 if node_values.iter().all(|v| !v.equivalent(&value)) {
147 node_values.insert(value)
148 }
149 }
150 } else {
151 let values = values.into_iter();
152 let mut node_values: PropertyObjects<T, B> =
153 Multiset::with_capacity(values.size_hint().0);
154 for value in values {
155 if node_values.iter().all(|v| !v.equivalent(&value)) {
156 node_values.insert(value)
157 }
158 }
159
160 self.0.insert(prop, node_values);
161 }
162 }
163
164 pub fn set(&mut self, prop: Id<T, B>, values: PropertyObjects<T, B>) {
165 self.0.insert(prop, values);
166 }
167
168 pub fn extend_unique<I, O>(&mut self, iter: I)
169 where
170 I: IntoIterator<Item = (Id<T, B>, O)>,
171 O: IntoIterator<Item = IndexedObject<T, B>>,
172 {
173 for (prop, values) in iter {
174 self.insert_all_unique(prop, values)
175 }
176 }
177
178 #[inline(always)]
180 pub fn remove<Q: ?Sized + Hash + indexmap::Equivalent<Id<T, B>>>(
181 &mut self,
182 prop: &Q,
183 ) -> Option<PropertyObjects<T, B>> {
184 self.0.swap_remove(prop)
185 }
186}
187
188impl<T: Eq + Hash, B: Eq + Hash, O> FromIterator<(Id<T, B>, O)> for Properties<T, B>
189where
190 O: IntoIterator<Item = IndexedObject<T, B>>,
191{
192 fn from_iter<I: IntoIterator<Item = (Id<T, B>, O)>>(iter: I) -> Self {
193 let mut result = Self::default();
194 for (id, values) in iter {
195 result.insert_all(id, values);
196 }
197 result
198 }
199}
200
201impl<T: Eq + Hash, B: Eq + Hash> TryFromJson<T, B> for Properties<T, B> {
202 fn try_from_json_in(
203 vocabulary: &mut impl VocabularyMut<Iri = T, BlankId = B>,
204 value: json_syntax::Value,
205 ) -> Result<Self, InvalidExpandedJson> {
206 match value {
207 json_syntax::Value::Object(object) => Self::try_from_json_object_in(vocabulary, object),
208 _ => Err(InvalidExpandedJson::InvalidObject),
209 }
210 }
211}
212
213impl<T: Eq + Hash, B: Eq + Hash> TryFromJsonObject<T, B> for Properties<T, B> {
214 fn try_from_json_object_in(
215 vocabulary: &mut impl VocabularyMut<Iri = T, BlankId = B>,
216 object: json_syntax::Object,
217 ) -> Result<Self, InvalidExpandedJson> {
218 let mut result = Self::new();
219
220 for entry in object {
221 let prop = Id::from_string_in(vocabulary, entry.key.to_string());
222 let objects: Vec<IndexedObject<T, B>> = Vec::try_from_json_in(vocabulary, entry.value)?;
223 result.insert_all(prop, objects)
224 }
225
226 Ok(result)
227 }
228}
229
230impl<T: Hash, B: Hash> Hash for Properties<T, B> {
231 #[inline(always)]
232 fn hash<H: Hasher>(&self, h: &mut H) {
233 crate::utils::hash_map(&self.0, h)
234 }
235}
236
237impl<T: Eq + Hash, B: Eq + Hash> Extend<(Id<T, B>, Vec<IndexedObject<T, B>>)> for Properties<T, B> {
238 fn extend<I>(&mut self, iter: I)
239 where
240 I: IntoIterator<Item = (Id<T, B>, Vec<IndexedObject<T, B>>)>,
241 {
242 for (prop, values) in iter {
243 self.insert_all(prop, values)
244 }
245 }
246}
247
248pub type Binding<T, B> = (Id<T, B>, PropertyObjects<T, B>);
251
252pub type BindingRef<'a, T, B> = (&'a Id<T, B>, &'a [IndexedObject<T, B>]);
255
256pub type BindingMut<'a, T, B> = (&'a Id<T, B>, &'a mut PropertyObjects<T, B>);
259
260impl<T, B> IntoIterator for Properties<T, B> {
261 type Item = Binding<T, B>;
262 type IntoIter = IntoIter<T, B>;
263
264 #[inline(always)]
265 fn into_iter(self) -> Self::IntoIter {
266 self.0.into_iter()
267 }
268}
269
270impl<'a, T, B> IntoIterator for &'a Properties<T, B> {
271 type Item = BindingRef<'a, T, B>;
272 type IntoIter = Iter<'a, T, B>;
273
274 #[inline(always)]
275 fn into_iter(self) -> Self::IntoIter {
276 self.iter()
277 }
278}
279
280impl<'a, T, B> IntoIterator for &'a mut Properties<T, B> {
281 type Item = BindingMut<'a, T, B>;
282 type IntoIter = IterMut<'a, T, B>;
283
284 #[inline(always)]
285 fn into_iter(self) -> Self::IntoIter {
286 self.iter_mut()
287 }
288}
289
290pub type IntoIter<T, B> = indexmap::map::IntoIter<Id<T, B>, PropertyObjects<T, B>>;
294
295#[derive(Educe)]
299#[educe(Clone)]
300pub struct Iter<'a, T, B> {
301 inner: indexmap::map::Iter<'a, Id<T, B>, PropertyObjects<T, B>>,
302}
303
304impl<'a, T, B> Iterator for Iter<'a, T, B> {
305 type Item = BindingRef<'a, T, B>;
306
307 #[inline(always)]
308 fn size_hint(&self) -> (usize, Option<usize>) {
309 self.inner.size_hint()
310 }
311
312 #[inline(always)]
313 fn next(&mut self) -> Option<Self::Item> {
314 self.inner
315 .next()
316 .map(|(property, objects)| (property, objects.as_slice()))
317 }
318}
319
320impl<'a, T, B> ExactSizeIterator for Iter<'a, T, B> {}
321
322impl<'a, T, B> std::iter::FusedIterator for Iter<'a, T, B> {}
323
324pub type IterMut<'a, T, B> = indexmap::map::IterMut<'a, Id<T, B>, PropertyObjects<T, B>>;