1use super::{Multiset, Nodes};
2use crate::{
3 DefaultBuildHasher,
4 Id,
5 IndexMap,
6 IndexedNode,
7 object::{InvalidExpandedJson, TryFromJson, TryFromJsonObject},
8};
9use contextual::WithContext;
10use derive_where::derive_where;
11use iri_rs::IriBuf;
12use jsonld_syntax::IntoJsonWithContext;
13use rdfx::{
14 BlankIdBuf,
15 vocabulary::{Vocabulary, VocabularyMut},
16};
17use std::hash::{Hash, Hasher};
18
19pub type ReversePropertyNodes<T = IriBuf, B = BlankIdBuf> = Multiset<IndexedNode<T, B>>;
21
22#[derive(Debug, Clone)]
24#[derive_where(PartialEq; T: Eq + Hash, B: Eq + Hash)]
25pub struct ReverseProperties<T = IriBuf, B = BlankIdBuf>(IndexMap<Id<T, B>, ReversePropertyNodes<T, B>>);
26
27impl<T: Eq + Hash, B: Eq + Hash> Eq for ReverseProperties<T, B> {}
28
29impl<T, B> Default for ReverseProperties<T, B> {
30 fn default() -> Self {
31 Self::new()
32 }
33}
34
35impl<T, B> ReverseProperties<T, B> {
36 #[must_use]
38 pub fn new() -> Self {
39 Self(IndexMap::with_hasher(DefaultBuildHasher::default()))
40 }
41
42 #[inline(always)]
44 #[must_use]
45 pub fn len(&self) -> usize {
46 self.0.len()
47 }
48
49 #[inline(always)]
51 #[must_use]
52 pub fn is_empty(&self) -> bool {
53 self.0.is_empty()
54 }
55
56 #[inline(always)]
58 #[must_use]
59 pub fn iter(&self) -> Iter<'_, T, B> {
60 Iter { inner: self.0.iter() }
61 }
62
63 #[inline(always)]
65 pub fn iter_mut(&mut self) -> IterMut<'_, T, B> {
66 self.0.iter_mut()
67 }
68
69 #[inline(always)]
71 pub fn clear(&mut self) {
72 self.0.clear();
73 }
74}
75
76impl<T: Eq + Hash, B: Eq + Hash> ReverseProperties<T, B> {
77 #[inline(always)]
79 pub fn contains<Q: ?Sized + Hash + indexmap::Equivalent<Id<T, B>>>(&self, prop: &Q) -> bool {
80 self.0.get(prop).is_some()
81 }
82
83 #[inline(always)]
85 pub fn get<'a, Q: ?Sized + Hash + indexmap::Equivalent<Id<T, B>>>(&self, prop: &Q) -> Nodes<'_, T, B>
86 where
87 T: 'a,
88 {
89 match self.0.get(prop) {
90 Some(values) => Nodes::new(Some(values.iter())),
91 None => Nodes::new(None),
92 }
93 }
94
95 #[inline(always)]
100 pub fn get_any<'a, Q: ?Sized + Hash + indexmap::Equivalent<Id<T, B>>>(&self, prop: &Q) -> Option<&IndexedNode<T, B>>
101 where
102 T: 'a,
103 {
104 match self.0.get(prop) {
105 Some(values) => values.iter().next(),
106 None => None,
107 }
108 }
109
110 #[inline(always)]
112 pub fn insert(&mut self, prop: Id<T, B>, value: IndexedNode<T, B>) {
113 if let Some(node_values) = self.0.get_mut(&prop) {
114 node_values.insert(value);
115 } else {
116 self.0.insert(prop, Multiset::singleton(value));
117 }
118 }
119
120 #[inline(always)]
122 pub fn insert_unique(&mut self, prop: Id<T, B>, value: IndexedNode<T, B>) {
123 if let Some(node_values) = self.0.get_mut(&prop) {
124 if node_values.iter().all(|v| !v.equivalent(&value)) {
125 node_values.insert(value);
126 }
127 } else {
128 self.0.insert(prop, Multiset::singleton(value));
129 }
130 }
131
132 #[inline(always)]
134 pub fn insert_all<Objects: IntoIterator<Item = IndexedNode<T, B>>>(&mut self, prop: Id<T, B>, values: Objects) {
135 if let Some(node_values) = self.0.get_mut(&prop) {
136 node_values.extend(values);
137 } else {
138 self.0.insert(prop, values.into_iter().collect());
139 }
140 }
141
142 #[inline(always)]
144 pub fn insert_all_unique<Nodes: IntoIterator<Item = IndexedNode<T, B>>>(&mut self, prop: Id<T, B>, values: Nodes) {
145 if let Some(node_values) = self.0.get_mut(&prop) {
146 for value in values {
147 if node_values.iter().all(|v| !v.equivalent(&value)) {
148 node_values.insert(value);
149 }
150 }
151 } else {
152 let values = values.into_iter();
153 let mut node_values: ReversePropertyNodes<T, B> = 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: ReversePropertyNodes<T, B>) {
166 self.0.insert(prop, values);
167 }
168
169 pub fn extend_unique<N>(&mut self, iter: impl IntoIterator<Item = (Id<T, B>, N)>)
172 where
173 N: IntoIterator<Item = IndexedNode<T, B>>,
174 {
175 for (prop, values) in iter {
176 self.insert_all_unique(prop, values);
177 }
178 }
179
180 #[inline(always)]
182 pub fn remove(&mut self, prop: &Id<T, B>) -> Option<ReversePropertyNodes<T, B>> {
183 self.0.shift_remove(prop)
184 }
185}
186
187impl<T: Eq + Hash, B: Eq + Hash, N> FromIterator<(Id<T, B>, N)> for ReverseProperties<T, B>
188where
189 N: IntoIterator<Item = IndexedNode<T, B>>,
190{
191 fn from_iter<I: IntoIterator<Item = (Id<T, B>, N)>>(iter: I) -> Self {
192 let mut result = Self::default();
193 for (id, values) in iter {
194 result.insert_all(id, values);
195 }
196 result
197 }
198}
199
200impl<T: Eq + Hash, B: Eq + Hash> TryFromJson<T, B> for ReverseProperties<T, B> {
201 fn try_from_json_in(vocabulary: &mut impl VocabularyMut<Iri = T, BlankId = B>, value: jstrict::Value) -> Result<Self, InvalidExpandedJson> {
202 match value {
203 jstrict::Value::Object(object) => Self::try_from_json_object_in(vocabulary, object),
204 _ => Err(InvalidExpandedJson::InvalidObject),
205 }
206 }
207}
208
209impl<T: Eq + Hash, B: Eq + Hash> TryFromJsonObject<T, B> for ReverseProperties<T, B> {
210 fn try_from_json_object_in(vocabulary: &mut impl VocabularyMut<Iri = T, BlankId = B>, object: jstrict::Object) -> Result<Self, InvalidExpandedJson> {
211 let mut result = Self::new();
212
213 for entry in object {
214 let prop = Id::from_string_in(vocabulary, entry.key.to_string());
215 let nodes: Vec<IndexedNode<T, B>> = Vec::try_from_json_in(vocabulary, entry.value)?;
216 result.insert_all(prop, nodes);
217 }
218
219 Ok(result)
220 }
221}
222
223impl<T: Hash, B: Hash> Hash for ReverseProperties<T, B> {
224 #[inline(always)]
225 fn hash<H: Hasher>(&self, h: &mut H) {
226 crate::utils::hash_map(&self.0, h);
227 }
228}
229
230impl<T: Eq + Hash, B: Eq + Hash> Extend<(Id<T, B>, Vec<IndexedNode<T, B>>)> for ReverseProperties<T, B> {
231 fn extend<I>(&mut self, iter: I)
232 where
233 I: IntoIterator<Item = (Id<T, B>, Vec<IndexedNode<T, B>>)>,
234 {
235 for (prop, values) in iter {
236 self.insert_all(prop, values);
237 }
238 }
239}
240
241pub type ReverseBinding<T, B> = (Id<T, B>, ReversePropertyNodes<T, B>);
244
245pub type ReverseBindingRef<'a, T, B> = (&'a Id<T, B>, &'a [IndexedNode<T, B>]);
248
249pub type ReverseBindingMut<'a, T, B> = (&'a Id<T, B>, &'a mut ReversePropertyNodes<T, B>);
252
253impl<T, B> IntoIterator for ReverseProperties<T, B> {
254 type Item = ReverseBinding<T, B>;
255 type IntoIter = IntoIter<T, B>;
256
257 #[inline(always)]
258 fn into_iter(self) -> Self::IntoIter {
259 self.0.into_iter()
260 }
261}
262
263impl<'a, T, B> IntoIterator for &'a ReverseProperties<T, B> {
264 type Item = ReverseBindingRef<'a, T, B>;
265 type IntoIter = Iter<'a, T, B>;
266
267 #[inline(always)]
268 fn into_iter(self) -> Self::IntoIter {
269 self.iter()
270 }
271}
272
273impl<'a, T, B> IntoIterator for &'a mut ReverseProperties<T, B> {
274 type Item = ReverseBindingMut<'a, T, B>;
275 type IntoIter = IterMut<'a, T, B>;
276
277 #[inline(always)]
278 fn into_iter(self) -> Self::IntoIter {
279 self.iter_mut()
280 }
281}
282
283pub type IntoIter<T, B> = indexmap::map::IntoIter<Id<T, B>, ReversePropertyNodes<T, B>>;
287
288#[derive_where(Clone)]
292pub struct Iter<'a, T, B> {
293 inner: indexmap::map::Iter<'a, Id<T, B>, ReversePropertyNodes<T, B>>,
294}
295
296impl<'a, T, B> Iterator for Iter<'a, T, B> {
297 type Item = ReverseBindingRef<'a, T, B>;
298
299 #[inline(always)]
300 fn size_hint(&self) -> (usize, Option<usize>) {
301 self.inner.size_hint()
302 }
303
304 #[inline(always)]
305 fn next(&mut self) -> Option<Self::Item> {
306 self.inner.next().map(|(property, objects)| (property, objects.as_slice()))
307 }
308}
309
310impl<T, B> ExactSizeIterator for Iter<'_, T, B> {}
311
312impl<T, B> std::iter::FusedIterator for Iter<'_, T, B> {}
313
314pub type IterMut<'a, T, B> = indexmap::map::IterMut<'a, Id<T, B>, ReversePropertyNodes<T, B>>;
319
320impl<T, B, N: Vocabulary<Iri = T, BlankId = B>> IntoJsonWithContext<N> for ReverseProperties<T, B> {
321 fn into_json_with(self, vocabulary: &N) -> jstrict::Value {
322 let mut obj = jstrict::Object::new();
323
324 for (prop, nodes) in self {
325 obj.insert(prop.with(vocabulary).to_string().into(), nodes.into_json_with(vocabulary));
326 }
327
328 obj.into()
329 }
330}