Skip to main content

json_ld/core/object/node/
reverse_properties.rs

1use super::JsonLdNodes;
2use crate::{
3	JsonLdIndexedNode, JsonLdLenient, JsonLdVisit,
4	object::{JsonLdObjectMut, JsonLdObjectRef},
5};
6use btree_indexmap::{BTreeIndexMap, BTreeIndexMultiSet, Comparable};
7use educe::Educe;
8use rdf_syntax::Id;
9use std::hash::Hash;
10
11pub type JsonLdReversePropertyNodes = BTreeIndexMultiSet<JsonLdIndexedNode>;
12
13/// Reverse properties of a node object, and their associated nodes.
14#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
15#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
16#[cfg_attr(feature = "serde", serde(transparent))]
17pub struct JsonLdReverseProperties(BTreeIndexMap<JsonLdLenient<Id>, JsonLdReversePropertyNodes>);
18
19impl Default for JsonLdReverseProperties {
20	fn default() -> Self {
21		Self::new()
22	}
23}
24
25impl JsonLdReverseProperties {
26	/// Creates an empty map.
27	pub fn new() -> Self {
28		Self(BTreeIndexMap::new())
29	}
30
31	/// Returns the number of reverse properties.
32	#[inline(always)]
33	pub fn len(&self) -> usize {
34		self.0.len()
35	}
36
37	/// Checks if there are no defined reverse properties.
38	#[inline(always)]
39	pub fn is_empty(&self) -> bool {
40		self.0.is_empty()
41	}
42
43	/// Returns an iterator over the reverse properties and their associated nodes.
44	#[inline(always)]
45	pub fn iter(&self) -> JsonLdReversePropertiesIter<'_> {
46		JsonLdReversePropertiesIter {
47			inner: self.0.iter(),
48		}
49	}
50
51	/// Returns an iterator over the reverse properties with a mutable reference to their associated nodes.
52	#[inline(always)]
53	pub fn iter_mut(&mut self) -> JsonLdReversePropertiesIterMut<'_> {
54		self.0.iter_mut()
55	}
56
57	/// Removes all reverse properties.
58	#[inline(always)]
59	pub fn clear(&mut self) {
60		self.0.clear()
61	}
62
63	/// Checks if the given reverse property is associated to any node.
64	#[inline(always)]
65	pub fn contains<Q: ?Sized + Hash + Comparable<JsonLdLenient<Id>>>(&self, prop: &Q) -> bool {
66		self.0.get(prop).is_some()
67	}
68
69	/// Returns an iterator over all the nodes associated to the given reverse property.
70	#[inline(always)]
71	pub fn get<Q: ?Sized + Hash + Comparable<JsonLdLenient<Id>>>(
72		&self,
73		prop: &Q,
74	) -> JsonLdNodes<'_> {
75		match self.0.get(prop) {
76			Some(values) => JsonLdNodes::new(Some(values.iter())),
77			None => JsonLdNodes::new(None),
78		}
79	}
80
81	/// Get one of the nodes associated to the given reverse property.
82	///
83	/// If multiple nodes are found, there are no guaranties on which node will be returned.
84	#[inline(always)]
85	pub fn get_any<Q: ?Sized + Hash + Comparable<JsonLdLenient<Id>>>(
86		&self,
87		prop: &Q,
88	) -> Option<&JsonLdIndexedNode> {
89		match self.0.get(prop) {
90			Some(values) => values.iter().next(),
91			None => None,
92		}
93	}
94
95	/// Associate the given node to the given reverse property.
96	#[inline(always)]
97	pub fn insert(&mut self, prop: JsonLdLenient<Id>, value: JsonLdIndexedNode) {
98		if let Some(node_values) = self.0.get_mut(&prop) {
99			node_values.insert(value);
100		} else {
101			self.0.insert(prop, BTreeIndexMultiSet::singleton(value));
102		}
103	}
104
105	/// Associate the given node to the given reverse property, unless it is already.
106	#[inline(always)]
107	pub fn insert_unique(&mut self, prop: JsonLdLenient<Id>, value: JsonLdIndexedNode) {
108		if let Some(node_values) = self.0.get_mut(&prop) {
109			if node_values.iter().all(|v| !v.equivalent(&value)) {
110				node_values.insert(value);
111			}
112		} else {
113			self.0.insert(prop, BTreeIndexMultiSet::singleton(value));
114		}
115	}
116
117	/// Associate all the given nodes to the given reverse property.
118	#[inline(always)]
119	pub fn insert_all<Objects: IntoIterator<Item = JsonLdIndexedNode>>(
120		&mut self,
121		prop: JsonLdLenient<Id>,
122		values: Objects,
123	) {
124		if let Some(node_values) = self.0.get_mut(&prop) {
125			node_values.extend(values);
126		} else {
127			self.0.insert(prop, values.into_iter().collect());
128		}
129	}
130
131	/// Associate all the given nodes to the given reverse property, unless it is already.
132	#[inline(always)]
133	pub fn insert_all_unique<Nodes: IntoIterator<Item = JsonLdIndexedNode>>(
134		&mut self,
135		prop: JsonLdLenient<Id>,
136		values: Nodes,
137	) {
138		if let Some(node_values) = self.0.get_mut(&prop) {
139			for value in values {
140				if node_values.iter().all(|v| !v.equivalent(&value)) {
141					node_values.insert(value);
142				}
143			}
144		} else {
145			let values = values.into_iter();
146			let mut node_values: JsonLdReversePropertyNodes =
147				BTreeIndexMultiSet::with_capacity(values.size_hint().0);
148			for value in values {
149				if node_values.iter().all(|v| !v.equivalent(&value)) {
150					node_values.insert(value);
151				}
152			}
153
154			self.0.insert(prop, node_values);
155		}
156	}
157
158	pub fn set(&mut self, prop: JsonLdLenient<Id>, values: JsonLdReversePropertyNodes) {
159		self.0.insert(prop, values);
160	}
161
162	pub fn extend_unique<N>(&mut self, iter: impl IntoIterator<Item = (JsonLdLenient<Id>, N)>)
163	where
164		N: IntoIterator<Item = JsonLdIndexedNode>,
165	{
166		for (prop, values) in iter {
167			self.insert_all_unique(prop, values)
168		}
169	}
170
171	/// Removes and returns all the values associated to the given reverse property.
172	#[inline(always)]
173	pub fn remove(&mut self, prop: &JsonLdLenient<Id>) -> Option<JsonLdReversePropertyNodes> {
174		self.0.swap_remove(prop)
175	}
176}
177
178impl JsonLdVisit for JsonLdReverseProperties {
179	fn visit_with(&self, f: &mut impl FnMut(JsonLdObjectRef)) {
180		for (_, t) in self {
181			t.visit_with(f);
182		}
183	}
184
185	fn visit_mut_with(&mut self, f: &mut impl FnMut(JsonLdObjectMut)) {
186		for (_, t) in self {
187			t.visit_mut_with(f);
188		}
189	}
190}
191
192impl<N> FromIterator<(JsonLdLenient<Id>, N)> for JsonLdReverseProperties
193where
194	N: IntoIterator<Item = JsonLdIndexedNode>,
195{
196	fn from_iter<I: IntoIterator<Item = (JsonLdLenient<Id>, N)>>(iter: I) -> Self {
197		let mut result = Self::default();
198		for (id, values) in iter {
199			result.insert_all(id, values);
200		}
201		result
202	}
203}
204
205impl Extend<(JsonLdLenient<Id>, Vec<JsonLdIndexedNode>)> for JsonLdReverseProperties {
206	fn extend<I>(&mut self, iter: I)
207	where
208		I: IntoIterator<Item = (JsonLdLenient<Id>, Vec<JsonLdIndexedNode>)>,
209	{
210		for (prop, values) in iter {
211			self.insert_all(prop, values)
212		}
213	}
214}
215
216/// Tuple type representing a reverse binding in a node object,
217/// associating a reverse property to some nodes.
218pub type JsonLdReverseBinding = (JsonLdLenient<Id>, JsonLdReversePropertyNodes);
219
220/// Tuple type representing a reference to a reverse binding in a node object,
221/// associating a reverse property to some nodes.
222pub type JsonLdReverseBindingRef<'a> = (&'a JsonLdLenient<Id>, &'a [JsonLdIndexedNode]);
223
224/// Tuple type representing a mutable reference to a reverse binding in a node object,
225/// associating a reverse property to some nodes, with a mutable access to the nodes.
226pub type JsonLdReverseBindingMut<'a> = (&'a JsonLdLenient<Id>, &'a mut JsonLdReversePropertyNodes);
227
228impl IntoIterator for JsonLdReverseProperties {
229	type Item = JsonLdReverseBinding;
230	type IntoIter = JsonLdReversePropertiesIntoIter;
231
232	#[inline(always)]
233	fn into_iter(self) -> Self::IntoIter {
234		self.0.into_iter()
235	}
236}
237
238impl<'a> IntoIterator for &'a JsonLdReverseProperties {
239	type Item = JsonLdReverseBindingRef<'a>;
240	type IntoIter = JsonLdReversePropertiesIter<'a>;
241
242	#[inline(always)]
243	fn into_iter(self) -> Self::IntoIter {
244		self.iter()
245	}
246}
247
248impl<'a> IntoIterator for &'a mut JsonLdReverseProperties {
249	type Item = JsonLdReverseBindingMut<'a>;
250	type IntoIter = JsonLdReversePropertiesIterMut<'a>;
251
252	#[inline(always)]
253	fn into_iter(self) -> Self::IntoIter {
254		self.iter_mut()
255	}
256}
257
258/// Iterator over the reverse properties of a node.
259///
260/// It is created by the [`JsonLdReverseProperties::into_iter`] function.
261pub type JsonLdReversePropertiesIntoIter =
262	btree_indexmap::map::IntoIter<JsonLdLenient<Id>, JsonLdReversePropertyNodes>;
263
264/// Iterator over the reverse properties of a node.
265///
266/// It is created by the [`JsonLdReverseProperties::iter`] function.
267#[derive(Educe)]
268#[educe(Clone)]
269pub struct JsonLdReversePropertiesIter<'a> {
270	inner: btree_indexmap::map::Iter<'a, JsonLdLenient<Id>, JsonLdReversePropertyNodes>,
271}
272
273impl<'a> Iterator for JsonLdReversePropertiesIter<'a> {
274	type Item = JsonLdReverseBindingRef<'a>;
275
276	#[inline(always)]
277	fn size_hint(&self) -> (usize, Option<usize>) {
278		self.inner.size_hint()
279	}
280
281	#[inline(always)]
282	fn next(&mut self) -> Option<Self::Item> {
283		self.inner
284			.next()
285			.map(|(property, objects)| (property, objects.as_slice()))
286	}
287}
288
289impl<'a> ExactSizeIterator for JsonLdReversePropertiesIter<'a> {}
290
291impl<'a> std::iter::FusedIterator for JsonLdReversePropertiesIter<'a> {}
292
293/// Iterator over the reverse properties of a node, giving a mutable reference
294/// to the associated nodes.
295///
296/// It is created by the [`JsonLdReverseProperties::iter_mut`] function.
297pub type JsonLdReversePropertiesIterMut<'a> =
298	btree_indexmap::map::IterMut<'a, JsonLdLenient<Id>, JsonLdReversePropertyNodes>;