Skip to main content

json_ld/core/object/node/
properties.rs

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