1use super::{Multiset, Nodes};
2use crate::{
3 object::{InvalidExpandedJson, TryFromJson, TryFromJsonObject},
4 Id, IndexedNode,
5};
6use contextual::WithContext;
7use educe::Educe;
8use indexmap::IndexMap;
9use iref::IriBuf;
10use json_ld_syntax::IntoJsonWithContext;
11use rdf_types::{BlankIdBuf, Vocabulary, VocabularyMut};
12use std::hash::{Hash, Hasher};
13
14pub type ReversePropertyNodes<T = IriBuf, B = BlankIdBuf> = Multiset<IndexedNode<T, B>>;
15
16#[derive(Educe, Debug, Clone)]
18#[educe(
19 PartialEq(bound = "T: Eq + Hash, B: Eq + Hash"),
20 Eq(bound = "T: Eq + Hash, B: Eq + Hash")
21)]
22pub struct ReverseProperties<T = IriBuf, B = BlankIdBuf>(
23 IndexMap<Id<T, B>, ReversePropertyNodes<T, B>>,
24);
25
26impl<T, B> Default for ReverseProperties<T, B> {
27 fn default() -> Self {
28 Self::new()
29 }
30}
31
32impl<T, B> ReverseProperties<T, B> {
33 pub fn new() -> Self {
35 Self(IndexMap::new())
36 }
37
38 #[inline(always)]
40 pub fn len(&self) -> usize {
41 self.0.len()
42 }
43
44 #[inline(always)]
46 pub fn is_empty(&self) -> bool {
47 self.0.is_empty()
48 }
49
50 #[inline(always)]
52 pub fn iter(&self) -> Iter<'_, T, B> {
53 Iter {
54 inner: self.0.iter(),
55 }
56 }
57
58 #[inline(always)]
60 pub fn iter_mut(&mut self) -> IterMut<'_, T, B> {
61 self.0.iter_mut()
62 }
63
64 #[inline(always)]
66 pub fn clear(&mut self) {
67 self.0.clear()
68 }
69}
70
71impl<T: Eq + Hash, B: Eq + Hash> ReverseProperties<T, B> {
72 #[inline(always)]
74 pub fn contains<Q: ?Sized + Hash + indexmap::Equivalent<Id<T, B>>>(&self, prop: &Q) -> bool {
75 self.0.get(prop).is_some()
76 }
77
78 #[inline(always)]
80 pub fn get<'a, Q: ?Sized + Hash + indexmap::Equivalent<Id<T, B>>>(
81 &self,
82 prop: &Q,
83 ) -> Nodes<T, B>
84 where
85 T: 'a,
86 {
87 match self.0.get(prop) {
88 Some(values) => Nodes::new(Some(values.iter())),
89 None => Nodes::new(None),
90 }
91 }
92
93 #[inline(always)]
97 pub fn get_any<'a, Q: ?Sized + Hash + indexmap::Equivalent<Id<T, B>>>(
98 &self,
99 prop: &Q,
100 ) -> 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>>>(
135 &mut self,
136 prop: Id<T, B>,
137 values: Objects,
138 ) {
139 if let Some(node_values) = self.0.get_mut(&prop) {
140 node_values.extend(values);
141 } else {
142 self.0.insert(prop, values.into_iter().collect());
143 }
144 }
145
146 #[inline(always)]
148 pub fn insert_all_unique<Nodes: IntoIterator<Item = IndexedNode<T, B>>>(
149 &mut self,
150 prop: Id<T, B>,
151 values: Nodes,
152 ) {
153 if let Some(node_values) = self.0.get_mut(&prop) {
154 for value in values {
155 if node_values.iter().all(|v| !v.equivalent(&value)) {
156 node_values.insert(value)
157 }
158 }
159 } else {
160 let values = values.into_iter();
161 let mut node_values: ReversePropertyNodes<T, B> =
162 Multiset::with_capacity(values.size_hint().0);
163 for value in values {
164 if node_values.iter().all(|v| !v.equivalent(&value)) {
165 node_values.insert(value)
166 }
167 }
168
169 self.0.insert(prop, node_values);
170 }
171 }
172
173 pub fn set(&mut self, prop: Id<T, B>, values: ReversePropertyNodes<T, B>) {
174 self.0.insert(prop, values);
175 }
176
177 pub fn extend_unique<N>(&mut self, iter: impl IntoIterator<Item = (Id<T, B>, N)>)
178 where
179 N: IntoIterator<Item = IndexedNode<T, B>>,
180 {
181 for (prop, values) in iter {
182 self.insert_all_unique(prop, values)
183 }
184 }
185
186 #[inline(always)]
188 pub fn remove(&mut self, prop: &Id<T, B>) -> Option<ReversePropertyNodes<T, B>> {
189 self.0.swap_remove(prop)
190 }
191}
192
193impl<T: Eq + Hash, B: Eq + Hash, N> FromIterator<(Id<T, B>, N)> for ReverseProperties<T, B>
194where
195 N: IntoIterator<Item = IndexedNode<T, B>>,
196{
197 fn from_iter<I: IntoIterator<Item = (Id<T, B>, N)>>(iter: I) -> Self {
198 let mut result = Self::default();
199 for (id, values) in iter {
200 result.insert_all(id, values);
201 }
202 result
203 }
204}
205
206impl<T: Eq + Hash, B: Eq + Hash> TryFromJson<T, B> for ReverseProperties<T, B> {
207 fn try_from_json_in(
208 vocabulary: &mut impl VocabularyMut<Iri = T, BlankId = B>,
209 value: json_syntax::Value,
210 ) -> Result<Self, InvalidExpandedJson> {
211 match value {
212 json_syntax::Value::Object(object) => Self::try_from_json_object_in(vocabulary, object),
213 _ => Err(InvalidExpandedJson::InvalidObject),
214 }
215 }
216}
217
218impl<T: Eq + Hash, B: Eq + Hash> TryFromJsonObject<T, B> for ReverseProperties<T, B> {
219 fn try_from_json_object_in(
220 vocabulary: &mut impl VocabularyMut<Iri = T, BlankId = B>,
221 object: json_syntax::Object,
222 ) -> Result<Self, InvalidExpandedJson> {
223 let mut result = Self::new();
224
225 for entry in object {
226 let prop = Id::from_string_in(vocabulary, entry.key.to_string());
227 let nodes: Vec<IndexedNode<T, B>> = Vec::try_from_json_in(vocabulary, entry.value)?;
228 result.insert_all(prop, nodes)
229 }
230
231 Ok(result)
232 }
233}
234
235impl<T: Hash, B: Hash> Hash for ReverseProperties<T, B> {
236 #[inline(always)]
237 fn hash<H: Hasher>(&self, h: &mut H) {
238 crate::utils::hash_map(&self.0, h)
239 }
240}
241
242impl<T: Eq + Hash, B: Eq + Hash> Extend<(Id<T, B>, Vec<IndexedNode<T, B>>)>
243 for ReverseProperties<T, B>
244{
245 fn extend<I>(&mut self, iter: I)
246 where
247 I: IntoIterator<Item = (Id<T, B>, Vec<IndexedNode<T, B>>)>,
248 {
249 for (prop, values) in iter {
250 self.insert_all(prop, values)
251 }
252 }
253}
254
255pub type ReverseBinding<T, B> = (Id<T, B>, ReversePropertyNodes<T, B>);
258
259pub type ReverseBindingRef<'a, T, B> = (&'a Id<T, B>, &'a [IndexedNode<T, B>]);
262
263pub type ReverseBindingMut<'a, T, B> = (&'a Id<T, B>, &'a mut ReversePropertyNodes<T, B>);
266
267impl<T, B> IntoIterator for ReverseProperties<T, B> {
268 type Item = ReverseBinding<T, B>;
269 type IntoIter = IntoIter<T, B>;
270
271 #[inline(always)]
272 fn into_iter(self) -> Self::IntoIter {
273 self.0.into_iter()
274 }
275}
276
277impl<'a, T, B> IntoIterator for &'a ReverseProperties<T, B> {
278 type Item = ReverseBindingRef<'a, T, B>;
279 type IntoIter = Iter<'a, T, B>;
280
281 #[inline(always)]
282 fn into_iter(self) -> Self::IntoIter {
283 self.iter()
284 }
285}
286
287impl<'a, T, B> IntoIterator for &'a mut ReverseProperties<T, B> {
288 type Item = ReverseBindingMut<'a, T, B>;
289 type IntoIter = IterMut<'a, T, B>;
290
291 #[inline(always)]
292 fn into_iter(self) -> Self::IntoIter {
293 self.iter_mut()
294 }
295}
296
297pub type IntoIter<T, B> = indexmap::map::IntoIter<Id<T, B>, ReversePropertyNodes<T, B>>;
301
302#[derive(Educe)]
306#[educe(Clone)]
307pub struct Iter<'a, T, B> {
308 inner: indexmap::map::Iter<'a, Id<T, B>, ReversePropertyNodes<T, B>>,
309}
310
311impl<'a, T, B> Iterator for Iter<'a, T, B> {
312 type Item = ReverseBindingRef<'a, T, B>;
313
314 #[inline(always)]
315 fn size_hint(&self) -> (usize, Option<usize>) {
316 self.inner.size_hint()
317 }
318
319 #[inline(always)]
320 fn next(&mut self) -> Option<Self::Item> {
321 self.inner
322 .next()
323 .map(|(property, objects)| (property, objects.as_slice()))
324 }
325}
326
327impl<'a, T, B> ExactSizeIterator for Iter<'a, T, B> {}
328
329impl<'a, T, B> std::iter::FusedIterator for Iter<'a, T, B> {}
330
331pub type IterMut<'a, T, B> = indexmap::map::IterMut<'a, Id<T, B>, ReversePropertyNodes<T, B>>;
336
337impl<T, B, N: Vocabulary<Iri = T, BlankId = B>> IntoJsonWithContext<N> for ReverseProperties<T, B> {
338 fn into_json_with(self, vocabulary: &N) -> json_syntax::Value {
339 let mut obj = json_syntax::Object::new();
340
341 for (prop, nodes) in self {
342 obj.insert(
343 prop.with(vocabulary).to_string().into(),
344 nodes.into_json_with(vocabulary),
345 );
346 }
347
348 obj.into()
349 }
350}