Skip to main content

json_ld/core/object/node/
mod.rs

1use crate::object::{JsonLdObjectMut, JsonLdObjectRef, JsonLdObjects};
2use crate::syntax::JsonLdKeyword;
3use crate::{
4	JsonLdIndexed, JsonLdIndexedObject, JsonLdLenient, JsonLdObject, JsonLdTerm, JsonLdVisit,
5	object,
6};
7use btree_indexmap::{BTreeIndexMultiSet, BTreeIndexSet, Comparable};
8use educe::Educe;
9use rdf_syntax::Id;
10use rdf_syntax::Iri;
11use std::convert::TryFrom;
12use std::hash::Hash;
13
14pub mod properties;
15pub mod reverse_properties;
16
17pub use properties::JsonLdProperties;
18pub use reverse_properties::JsonLdReverseProperties;
19
20pub type JsonLdGraph = BTreeIndexSet<JsonLdIndexedObject>;
21
22pub type JsonLdIncluded = BTreeIndexSet<JsonLdIndexedNode>;
23
24pub type JsonLdIndexedNode = JsonLdIndexed<JsonLdNode>;
25
26/// Node object.
27///
28/// A node object represents zero or more properties of a node in the graph serialized by a JSON-LD document.
29/// A node is defined by its identifier (`@id` field), types, properties and reverse properties.
30/// In addition, a node may represent a graph (`@graph field`) and includes nodes
31/// (`@included` field).
32// NOTE it may be better to use BTreeSet instead of HashSet to have some ordering?
33//      in which case the Json bound should be lifted.
34#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
35#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
36pub struct JsonLdNode {
37	/// Identifier.
38	///
39	/// This is the `@id` field.
40	#[cfg_attr(
41		feature = "serde",
42		serde(rename = "@id", default, skip_serializing_if = "Option::is_none")
43	)]
44	pub id: Option<JsonLdLenient<Id>>,
45
46	/// Types.
47	///
48	/// This is the `@type` field.
49	#[cfg_attr(
50		feature = "serde",
51		serde(rename = "@type", default, skip_serializing_if = "Option::is_none")
52	)]
53	pub types: Option<BTreeIndexMultiSet<JsonLdLenient<Id>>>,
54
55	/// Associated graph.
56	///
57	/// This is the `@graph` field.
58	#[cfg_attr(
59		feature = "serde",
60		serde(rename = "@graph", default, skip_serializing_if = "Option::is_none")
61	)]
62	pub graph: Option<JsonLdGraph>,
63
64	/// Included nodes.
65	///
66	/// This is the `@included` field.
67	#[cfg_attr(
68		feature = "serde",
69		serde(rename = "@included", default, skip_serializing_if = "Option::is_none")
70	)]
71	pub included: Option<JsonLdIncluded>,
72
73	/// Properties.
74	///
75	/// Any non-keyword field.
76	#[cfg_attr(feature = "serde", serde(flatten))]
77	pub properties: JsonLdProperties,
78
79	/// Reverse properties.
80	///
81	/// This is the `@reverse` field.
82	#[cfg_attr(
83		feature = "serde",
84		serde(rename = "@reverse", default, skip_serializing_if = "Option::is_none")
85	)]
86	pub reverse_properties: Option<JsonLdReverseProperties>,
87}
88
89impl Default for JsonLdNode {
90	#[inline(always)]
91	fn default() -> Self {
92		Self::new()
93	}
94}
95
96impl JsonLdNode {
97	/// Creates a new empty node.
98	#[inline(always)]
99	pub fn new() -> Self {
100		Self::new_with_id(None)
101	}
102
103	/// Creates a new empty node.
104	#[inline(always)]
105	pub fn new_with_id(id: Option<JsonLdLenient<Id>>) -> Self {
106		Self {
107			id,
108			types: None,
109			graph: None,
110			included: None,
111			properties: JsonLdProperties::new(),
112			reverse_properties: None,
113		}
114	}
115
116	/// Creates a new graph node.
117	pub fn new_graph(id: JsonLdLenient<Id>, graph: JsonLdGraph) -> Self {
118		Self {
119			id: Some(id),
120			types: None,
121			graph: Some(graph),
122			included: None,
123			properties: JsonLdProperties::new(),
124			reverse_properties: None,
125		}
126	}
127
128	/// Returns a mutable reference to the reverse properties of the node.
129	///
130	/// If no `@reverse` entry is present, one is created.
131	#[inline(always)]
132	pub fn reverse_properties_mut_or_default(&mut self) -> &mut JsonLdReverseProperties {
133		self.reverse_properties
134			.get_or_insert_with(JsonLdReverseProperties::default)
135	}
136
137	/// Returns a mutable reference to the included nodes.
138	///
139	/// If no `@included` entry is present, one is created.
140	#[inline(always)]
141	pub fn included_mut_or_default(&mut self) -> &mut JsonLdIncluded {
142		self.included.get_or_insert_with(JsonLdIncluded::default)
143	}
144
145	/// Get the node's as an IRI if possible.
146	///
147	/// Returns the node's IRI id if any. Returns `None` otherwise.
148	#[inline(always)]
149	pub fn as_iri(&self) -> Option<&Iri> {
150		if let Some(id) = &self.id {
151			id.as_iri()
152		} else {
153			None
154		}
155	}
156
157	/// Get the node's id, is any, as a string slice.
158	///
159	/// Returns `None` if the node has no `@id` field.
160	#[inline(always)]
161	pub fn as_str(&self) -> Option<&str> {
162		match self.as_iri() {
163			Some(iri) => Some(iri.as_ref()),
164			None => None,
165		}
166	}
167
168	/// Checks if the node has the given type.
169	#[inline]
170	pub fn has_type<U>(&self, ty: &U) -> bool
171	where
172		U: ?Sized + Comparable<JsonLdLenient<Id>>,
173	{
174		self.types.as_ref().is_some_and(|types| types.contains(ty))
175	}
176
177	/// Tests if the node is empty.
178	///
179	/// It is empty is every field other than `@id` is empty.
180	#[inline]
181	pub fn is_empty(&self) -> bool {
182		self.types.is_none()
183			&& self.graph.is_none()
184			&& self.included.is_none()
185			&& self.properties.is_empty()
186			&& self.reverse_properties.is_none()
187	}
188
189	/// Tests if the node is a graph object (has a `@graph` field, and optionally an `@id` field).
190	/// Note that node objects may have a @graph entry,
191	/// but are not considered graph objects if they include any other entries other than `@id`.
192	#[inline]
193	pub fn is_graph(&self) -> bool {
194		self.graph.is_some()
195			&& self.types.is_none()
196			&& self.included.is_none()
197			&& self.properties.is_empty()
198			&& self.reverse_properties.is_none()
199	}
200
201	/// Tests if the node is a simple graph object (a graph object without `@id` field)
202	#[inline(always)]
203	pub fn is_simple_graph(&self) -> bool {
204		self.id.is_none() && self.is_graph()
205	}
206
207	/// If the node is a graph object, get the graph.
208	#[inline(always)]
209	pub fn graph(&self) -> Option<&JsonLdGraph> {
210		self.graph.as_ref()
211	}
212
213	/// If the node is a graph object, get the mutable graph.
214	#[inline(always)]
215	pub fn graph_mut(&mut self) -> Option<&mut JsonLdGraph> {
216		self.graph.as_mut()
217	}
218
219	/// If the node is a graph object, get the graph.
220	#[inline(always)]
221	pub fn graph_entry(&self) -> Option<&JsonLdGraph> {
222		self.graph.as_ref()
223	}
224
225	/// If the node is a graph object, get the mutable graph.
226	#[inline(always)]
227	pub fn graph_entry_mut(&mut self) -> Option<&mut JsonLdGraph> {
228		self.graph.as_mut()
229	}
230
231	/// Set the graph.
232	#[inline(always)]
233	pub fn set_graph_entry(&mut self, graph: Option<JsonLdGraph>) {
234		self.graph = graph
235	}
236
237	/// Get the set of nodes included by this node.
238	///
239	/// This correspond to the `@included` field in the JSON representation.
240	#[inline(always)]
241	pub fn included_entry(&self) -> Option<&JsonLdIncluded> {
242		self.included.as_ref()
243	}
244
245	/// Get the mutable set of nodes included by this node.
246	///
247	/// This correspond to the `@included` field in the JSON representation.
248	#[inline(always)]
249	pub fn included_entry_mut(&mut self) -> Option<&mut JsonLdIncluded> {
250		self.included.as_mut()
251	}
252
253	/// Returns a reference to the set of `@included` nodes.
254	pub fn included(&self) -> Option<&JsonLdIncluded> {
255		self.included.as_ref()
256	}
257
258	/// Returns a mutable reference to the set of `@included` nodes.
259	pub fn included_mut(&mut self) -> Option<&mut JsonLdIncluded> {
260		self.included.as_mut()
261	}
262
263	/// Set the set of nodes included by the node.
264	#[inline(always)]
265	pub fn set_included(&mut self, included: Option<JsonLdIncluded>) {
266		self.included = included
267	}
268
269	/// Returns a reference to the properties of the node.
270	#[inline(always)]
271	pub fn properties(&self) -> &JsonLdProperties {
272		&self.properties
273	}
274
275	/// Returns a mutable reference to the properties of the node.
276	#[inline(always)]
277	pub fn properties_mut(&mut self) -> &mut JsonLdProperties {
278		&mut self.properties
279	}
280
281	/// Returns a reference to the properties of the node.
282	#[inline(always)]
283	pub fn reverse_properties(&self) -> Option<&JsonLdReverseProperties> {
284		self.reverse_properties.as_ref()
285	}
286
287	/// Returns a reference to the reverse properties of the node.
288	#[inline(always)]
289	pub fn reverse_properties_entry(&self) -> Option<&JsonLdReverseProperties> {
290		self.reverse_properties.as_ref()
291	}
292
293	/// Returns a mutable reference to the reverse properties of the node.
294	#[inline(always)]
295	pub fn reverse_properties_mut(&mut self) -> Option<&mut JsonLdReverseProperties> {
296		self.reverse_properties.as_mut()
297	}
298
299	pub fn set_reverse_properties(&mut self, reverse_properties: Option<JsonLdReverseProperties>) {
300		self.reverse_properties = reverse_properties
301	}
302
303	/// Tests if the node is an unnamed graph object.
304	///
305	/// Returns `true` is the only field of the object is a `@graph` field.
306	/// Returns `false` otherwise.
307	#[inline]
308	pub fn is_unnamed_graph(&self) -> bool {
309		self.graph.is_some()
310			&& self.id.is_none()
311			&& self.types.is_none()
312			&& self.included.is_none()
313			&& self.properties.is_empty()
314			&& self.reverse_properties.is_none()
315	}
316
317	/// Returns the node as an unnamed graph, if it is one.
318	///
319	/// The unnamed graph is returned as a set of indexed objects.
320	/// Fails and returns itself if the node is *not* an unnamed graph.
321	#[allow(clippy::result_large_err)]
322	#[inline(always)]
323	pub fn into_unnamed_graph(self) -> Result<JsonLdGraph, Self> {
324		if self.is_unnamed_graph() {
325			Ok(self.graph.unwrap())
326		} else {
327			Err(self)
328		}
329	}
330
331	pub fn entries(&self) -> JsonLdNodeEntries<'_> {
332		JsonLdNodeEntries {
333			id: self.id.as_ref(),
334			type_: self.types.as_ref(),
335			graph: self.graph.as_ref(),
336			included: self.included.as_ref(),
337			reverse: self.reverse_properties.as_ref(),
338			properties: self.properties.iter(),
339		}
340	}
341
342	/// Checks if the node object has the given term as key.
343	///
344	/// # Example
345	/// ```
346	/// use json_ld::{JsonLdNode, JsonLdTerm};
347	/// use json_ld::syntax::JsonLdKeyword;
348	///
349	/// let node = JsonLdNode::new();
350	///
351	/// // Checks if the JSON object representation of the node has an `@id` key.
352	/// if node.has_key(&JsonLdTerm::Keyword(JsonLdKeyword::Id)) {
353	///   // ...
354	/// }
355	/// ```
356	#[inline(always)]
357	pub fn has_key(&self, key: &JsonLdTerm) -> bool {
358		match key {
359			JsonLdTerm::Keyword(JsonLdKeyword::Id) => self.id.is_some(),
360			JsonLdTerm::Keyword(JsonLdKeyword::Type) => self.types.is_some(),
361			JsonLdTerm::Keyword(JsonLdKeyword::Graph) => self.graph.is_some(),
362			JsonLdTerm::Keyword(JsonLdKeyword::Included) => self.included.is_some(),
363			JsonLdTerm::Keyword(JsonLdKeyword::Reverse) => self.reverse_properties.is_some(),
364			JsonLdTerm::Id(prop) => self.properties.contains(prop),
365			_ => false,
366		}
367	}
368
369	/// Get all the objects associated to the node with the given property.
370	#[inline(always)]
371	pub fn get<Q>(&self, prop: &Q) -> JsonLdObjects<'_>
372	where
373		Q: ?Sized + Hash + Comparable<JsonLdLenient<Id>>,
374	{
375		self.properties.get(prop)
376	}
377
378	/// Get one of the objects associated to the node with the given property.
379	///
380	/// If multiple objects are attached to the node with this property, there are no guaranties
381	/// on which object will be returned.
382	#[inline(always)]
383	pub fn get_any<Q>(&self, prop: &Q) -> Option<&JsonLdIndexedObject>
384	where
385		Q: ?Sized + Hash + Comparable<JsonLdLenient<Id>>,
386	{
387		self.properties.get_any(prop)
388	}
389
390	/// Associates the given object to the node through the given property.
391	#[inline(always)]
392	pub fn insert(&mut self, prop: JsonLdLenient<Id>, value: JsonLdIndexedObject) {
393		self.properties.insert(prop, value)
394	}
395
396	/// Associates all the given objects to the node through the given property.
397	///
398	/// If there already exists objects associated to the given reverse property,
399	/// `reverse_value` is added to the list. Duplicate objects are not removed.
400	#[inline(always)]
401	pub fn insert_all<Objects: IntoIterator<Item = JsonLdIndexedObject>>(
402		&mut self,
403		prop: JsonLdLenient<Id>,
404		values: Objects,
405	) {
406		self.properties.insert_all(prop, values)
407	}
408
409	pub fn reverse_properties_or_insert(
410		&mut self,
411		props: JsonLdReverseProperties,
412	) -> &mut JsonLdReverseProperties {
413		self.reverse_properties.get_or_insert(props)
414	}
415
416	pub fn reverse_properties_or_default(&mut self) -> &mut JsonLdReverseProperties {
417		self.reverse_properties
418			.get_or_insert_with(JsonLdReverseProperties::default)
419	}
420
421	pub fn reverse_properties_or_insert_with(
422		&mut self,
423		f: impl FnOnce() -> JsonLdReverseProperties,
424	) -> &mut JsonLdReverseProperties {
425		self.reverse_properties.get_or_insert_with(f)
426	}
427
428	/// Equivalence operator.
429	///
430	/// Equivalence is different from equality for anonymous objects.
431	/// Anonymous node objects have an implicit unlabeled blank nodes and thus never equivalent.
432	pub fn equivalent(&self, other: &Self) -> bool {
433		if self.id.is_some() && other.id.is_some() {
434			self == other
435		} else {
436			false
437		}
438	}
439}
440
441impl JsonLdVisit for JsonLdNode {
442	fn visit_with(&self, f: &mut impl FnMut(JsonLdObjectRef)) {
443		f(JsonLdObjectRef::Node(self));
444		self.graph.visit_with(f);
445		self.included.visit_with(f);
446		self.properties.visit_with(f);
447		self.reverse_properties.visit_with(f);
448	}
449
450	fn visit_mut_with(&mut self, f: &mut impl FnMut(JsonLdObjectMut)) {
451		f(JsonLdObjectMut::Node(self));
452		self.graph.visit_mut_with(f);
453		self.included.visit_mut_with(f);
454		self.properties.visit_mut_with(f);
455		self.reverse_properties.visit_mut_with(f);
456	}
457}
458
459impl JsonLdIndexed<JsonLdNode> {
460	pub fn entries(&self) -> JsonLdIndexedNodeEntries<'_> {
461		JsonLdIndexedNodeEntries {
462			index: self.index(),
463			inner: self.inner().entries(),
464		}
465	}
466}
467
468impl JsonLdIndexed<JsonLdNode> {
469	pub fn equivalent(&self, other: &Self) -> bool {
470		self.index() == other.index() && self.inner().equivalent(other.inner())
471	}
472}
473
474#[derive(Educe, PartialEq, Eq)]
475#[educe(Clone, Copy)]
476pub enum JsonLdNodeEntryKeyRef<'a> {
477	Id,
478	Type,
479	Graph,
480	Included,
481	Reverse,
482	Property(&'a JsonLdLenient<Id>),
483}
484
485impl<'a> JsonLdNodeEntryKeyRef<'a> {
486	pub fn into_keyword(self) -> Option<JsonLdKeyword> {
487		match self {
488			Self::Id => Some(JsonLdKeyword::Id),
489			Self::Type => Some(JsonLdKeyword::Type),
490			Self::Graph => Some(JsonLdKeyword::Graph),
491			Self::Included => Some(JsonLdKeyword::Included),
492			Self::Reverse => Some(JsonLdKeyword::Reverse),
493			Self::Property(_) => None,
494		}
495	}
496
497	pub fn as_keyword(&self) -> Option<JsonLdKeyword> {
498		self.into_keyword()
499	}
500
501	pub fn into_str(self) -> &'a str {
502		match self {
503			Self::Id => "@id",
504			Self::Type => "@type",
505			Self::Graph => "@graph",
506			Self::Included => "@included",
507			Self::Reverse => "@reverse",
508			Self::Property(p) => p.as_str(),
509		}
510	}
511
512	pub fn as_str(&self) -> &'a str {
513		self.into_str()
514	}
515}
516
517#[derive(Educe)]
518#[educe(Clone, Copy)]
519pub enum JsonLdNodeEntryValueRef<'a> {
520	Id(&'a JsonLdLenient<Id>),
521	Type(&'a BTreeIndexMultiSet<JsonLdLenient<Id>>),
522	Graph(&'a BTreeIndexSet<JsonLdIndexedObject>),
523	Included(&'a BTreeIndexSet<JsonLdIndexedNode>),
524	Reverse(&'a JsonLdReverseProperties),
525	Property(&'a [JsonLdIndexedObject]),
526}
527
528impl<'a> JsonLdNodeEntryValueRef<'a> {
529	pub fn is_json_array(&self) -> bool {
530		matches!(
531			self,
532			Self::Type(_) | Self::Graph(_) | Self::Included(_) | Self::Property(_)
533		)
534	}
535
536	pub fn is_json_object(&self) -> bool {
537		matches!(self, Self::Reverse(_))
538	}
539}
540
541#[derive(Educe)]
542#[educe(Clone, Copy)]
543pub enum JsonLdNodeEntryRef<'a> {
544	Id(&'a JsonLdLenient<Id>),
545	Type(&'a BTreeIndexMultiSet<JsonLdLenient<Id>>),
546	Graph(&'a JsonLdGraph),
547	Included(&'a JsonLdIncluded),
548	Reverse(&'a JsonLdReverseProperties),
549	Property(&'a JsonLdLenient<Id>, &'a [JsonLdIndexedObject]),
550}
551
552impl<'a> JsonLdNodeEntryRef<'a> {
553	pub fn into_key(self) -> JsonLdNodeEntryKeyRef<'a> {
554		match self {
555			Self::Id(_) => JsonLdNodeEntryKeyRef::Id,
556			Self::Type(_) => JsonLdNodeEntryKeyRef::Type,
557			Self::Graph(_) => JsonLdNodeEntryKeyRef::Graph,
558			Self::Included(_) => JsonLdNodeEntryKeyRef::Included,
559			Self::Reverse(_) => JsonLdNodeEntryKeyRef::Reverse,
560			Self::Property(k, _) => JsonLdNodeEntryKeyRef::Property(k),
561		}
562	}
563
564	pub fn key(&self) -> JsonLdNodeEntryKeyRef<'a> {
565		self.into_key()
566	}
567
568	pub fn into_value(self) -> JsonLdNodeEntryValueRef<'a> {
569		match self {
570			Self::Id(v) => JsonLdNodeEntryValueRef::Id(v),
571			Self::Type(v) => JsonLdNodeEntryValueRef::Type(v),
572			Self::Graph(v) => JsonLdNodeEntryValueRef::Graph(v),
573			Self::Included(v) => JsonLdNodeEntryValueRef::Included(v),
574			Self::Reverse(v) => JsonLdNodeEntryValueRef::Reverse(v),
575			Self::Property(_, v) => JsonLdNodeEntryValueRef::Property(v),
576		}
577	}
578
579	pub fn value(&self) -> JsonLdNodeEntryValueRef<'a> {
580		self.into_value()
581	}
582
583	pub fn into_key_value(self) -> (JsonLdNodeEntryKeyRef<'a>, JsonLdNodeEntryValueRef<'a>) {
584		match self {
585			Self::Id(v) => (JsonLdNodeEntryKeyRef::Id, JsonLdNodeEntryValueRef::Id(v)),
586			Self::Type(v) => (
587				JsonLdNodeEntryKeyRef::Type,
588				JsonLdNodeEntryValueRef::Type(v),
589			),
590			Self::Graph(v) => (
591				JsonLdNodeEntryKeyRef::Graph,
592				JsonLdNodeEntryValueRef::Graph(v),
593			),
594			Self::Included(v) => (
595				JsonLdNodeEntryKeyRef::Included,
596				JsonLdNodeEntryValueRef::Included(v),
597			),
598			Self::Reverse(v) => (
599				JsonLdNodeEntryKeyRef::Reverse,
600				JsonLdNodeEntryValueRef::Reverse(v),
601			),
602			Self::Property(k, v) => (
603				JsonLdNodeEntryKeyRef::Property(k),
604				JsonLdNodeEntryValueRef::Property(v),
605			),
606		}
607	}
608
609	pub fn as_key_value(&self) -> (JsonLdNodeEntryKeyRef<'a>, JsonLdNodeEntryValueRef<'a>) {
610		match self {
611			Self::Id(v) => (JsonLdNodeEntryKeyRef::Id, JsonLdNodeEntryValueRef::Id(v)),
612			Self::Type(v) => (
613				JsonLdNodeEntryKeyRef::Type,
614				JsonLdNodeEntryValueRef::Type(v),
615			),
616			Self::Graph(v) => (
617				JsonLdNodeEntryKeyRef::Graph,
618				JsonLdNodeEntryValueRef::Graph(v),
619			),
620			Self::Included(v) => (
621				JsonLdNodeEntryKeyRef::Included,
622				JsonLdNodeEntryValueRef::Included(v),
623			),
624			Self::Reverse(v) => (
625				JsonLdNodeEntryKeyRef::Reverse,
626				JsonLdNodeEntryValueRef::Reverse(v),
627			),
628			Self::Property(k, v) => (
629				JsonLdNodeEntryKeyRef::Property(k),
630				JsonLdNodeEntryValueRef::Property(v),
631			),
632		}
633	}
634}
635
636#[derive(Educe)]
637#[educe(Clone)]
638pub struct JsonLdNodeEntries<'a> {
639	id: Option<&'a JsonLdLenient<Id>>,
640	type_: Option<&'a BTreeIndexMultiSet<JsonLdLenient<Id>>>,
641	graph: Option<&'a JsonLdGraph>,
642	included: Option<&'a JsonLdIncluded>,
643	reverse: Option<&'a JsonLdReverseProperties>,
644	properties: properties::JsonLdPropertiesIter<'a>,
645}
646
647impl<'a> Iterator for JsonLdNodeEntries<'a> {
648	type Item = JsonLdNodeEntryRef<'a>;
649
650	fn size_hint(&self) -> (usize, Option<usize>) {
651		let mut len = self.properties.len();
652
653		if self.id.is_some() {
654			len += 1
655		}
656
657		if self.type_.is_some() {
658			len += 1
659		}
660
661		if self.graph.is_some() {
662			len += 1
663		}
664
665		if self.included.is_some() {
666			len += 1
667		}
668
669		if self.reverse.is_some() {
670			len += 1
671		}
672
673		(len, Some(len))
674	}
675
676	fn next(&mut self) -> Option<Self::Item> {
677		self.id.take().map(JsonLdNodeEntryRef::Id).or_else(|| {
678			self.type_.take().map(JsonLdNodeEntryRef::Type).or_else(|| {
679				self.graph
680					.take()
681					.map(JsonLdNodeEntryRef::Graph)
682					.or_else(|| {
683						self.included
684							.take()
685							.map(JsonLdNodeEntryRef::Included)
686							.or_else(|| {
687								self.reverse
688									.take()
689									.map(JsonLdNodeEntryRef::Reverse)
690									.or_else(|| {
691										self.properties
692											.next()
693											.map(|(k, v)| JsonLdNodeEntryRef::Property(k, v))
694									})
695							})
696					})
697			})
698		})
699	}
700}
701
702impl<'a> ExactSizeIterator for JsonLdNodeEntries<'a> {}
703
704#[derive(Educe)]
705#[educe(Clone)]
706pub struct JsonLdIndexedNodeEntries<'a> {
707	index: Option<&'a str>,
708	inner: JsonLdNodeEntries<'a>,
709}
710
711impl<'a> Iterator for JsonLdIndexedNodeEntries<'a> {
712	type Item = JsonLdIndexedNodeEntryRef<'a>;
713
714	fn size_hint(&self) -> (usize, Option<usize>) {
715		let len = self.inner.len() + usize::from(self.index.is_some());
716		(len, Some(len))
717	}
718
719	fn next(&mut self) -> Option<Self::Item> {
720		self.index
721			.take()
722			.map(JsonLdIndexedNodeEntryRef::Index)
723			.or_else(|| self.inner.next().map(JsonLdIndexedNodeEntryRef::Node))
724	}
725}
726
727impl<'a> ExactSizeIterator for JsonLdIndexedNodeEntries<'a> {}
728
729#[derive(Educe, PartialEq, Eq)]
730#[educe(Clone, Copy)]
731pub enum JsonLdIndexedNodeEntryKeyRef<'a> {
732	Index,
733	Node(JsonLdNodeEntryKeyRef<'a>),
734}
735
736impl<'a> JsonLdIndexedNodeEntryKeyRef<'a> {
737	pub fn into_keyword(self) -> Option<JsonLdKeyword> {
738		match self {
739			Self::Index => Some(JsonLdKeyword::Index),
740			Self::Node(e) => e.into_keyword(),
741		}
742	}
743
744	pub fn as_keyword(&self) -> Option<JsonLdKeyword> {
745		self.into_keyword()
746	}
747
748	pub fn into_str(self) -> &'a str {
749		match self {
750			Self::Index => "@index",
751			Self::Node(e) => e.into_str(),
752		}
753	}
754
755	pub fn as_str(&self) -> &'a str {
756		self.into_str()
757	}
758}
759
760#[derive(Educe)]
761#[educe(Clone, Copy)]
762pub enum JsonLdIndexedNodeEntryValueRef<'a> {
763	Index(&'a str),
764	Node(JsonLdNodeEntryValueRef<'a>),
765}
766
767#[derive(Educe)]
768#[educe(Clone, Copy)]
769pub enum JsonLdIndexedNodeEntryRef<'a> {
770	Index(&'a str),
771	Node(JsonLdNodeEntryRef<'a>),
772}
773
774impl<'a> JsonLdIndexedNodeEntryRef<'a> {
775	pub fn into_key(self) -> JsonLdIndexedNodeEntryKeyRef<'a> {
776		match self {
777			Self::Index(_) => JsonLdIndexedNodeEntryKeyRef::Index,
778			Self::Node(e) => JsonLdIndexedNodeEntryKeyRef::Node(e.key()),
779		}
780	}
781
782	pub fn key(&self) -> JsonLdIndexedNodeEntryKeyRef<'a> {
783		self.into_key()
784	}
785
786	pub fn into_value(self) -> JsonLdIndexedNodeEntryValueRef<'a> {
787		match self {
788			Self::Index(v) => JsonLdIndexedNodeEntryValueRef::Index(v),
789			Self::Node(e) => JsonLdIndexedNodeEntryValueRef::Node(e.value()),
790		}
791	}
792
793	pub fn value(&self) -> JsonLdIndexedNodeEntryValueRef<'a> {
794		self.into_value()
795	}
796
797	pub fn into_key_value(
798		self,
799	) -> (
800		JsonLdIndexedNodeEntryKeyRef<'a>,
801		JsonLdIndexedNodeEntryValueRef<'a>,
802	) {
803		match self {
804			Self::Index(v) => (
805				JsonLdIndexedNodeEntryKeyRef::Index,
806				JsonLdIndexedNodeEntryValueRef::Index(v),
807			),
808			Self::Node(e) => {
809				let (k, v) = e.into_key_value();
810				(
811					JsonLdIndexedNodeEntryKeyRef::Node(k),
812					JsonLdIndexedNodeEntryValueRef::Node(v),
813				)
814			}
815		}
816	}
817
818	pub fn as_key_value(
819		&self,
820	) -> (
821		JsonLdIndexedNodeEntryKeyRef<'a>,
822		JsonLdIndexedNodeEntryValueRef<'a>,
823	) {
824		self.into_key_value()
825	}
826}
827
828impl object::AnyJsonLdObject for JsonLdNode {
829	#[inline(always)]
830	fn as_ref(&self) -> object::JsonLdObjectRef<'_> {
831		object::JsonLdObjectRef::Node(self)
832	}
833}
834
835impl TryFrom<JsonLdObject> for JsonLdNode {
836	type Error = JsonLdObject;
837
838	#[inline(always)]
839	fn try_from(obj: JsonLdObject) -> Result<JsonLdNode, JsonLdObject> {
840		match obj {
841			JsonLdObject::Node(node) => Ok(*node),
842			obj => Err(obj),
843		}
844	}
845}
846
847/// Iterator through indexed nodes.
848pub struct JsonLdNodes<'a>(Option<std::slice::Iter<'a, JsonLdIndexedNode>>);
849
850impl<'a> JsonLdNodes<'a> {
851	#[inline(always)]
852	pub(crate) fn new(inner: Option<std::slice::Iter<'a, JsonLdIndexedNode>>) -> Self {
853		Self(inner)
854	}
855}
856
857impl<'a> Iterator for JsonLdNodes<'a> {
858	type Item = &'a JsonLdIndexedNode;
859
860	#[inline(always)]
861	fn next(&mut self) -> Option<&'a JsonLdIndexedNode> {
862		match &mut self.0 {
863			None => None,
864			Some(it) => it.next(),
865		}
866	}
867}