Skip to main content

jsonld_core/object/node/
mod.rs

1use super::{InvalidExpandedJson, Traverse, TryFromJson, TryFromJsonObject};
2use crate::{HashMap, Id, Indexed, IndexedObject, Object, Objects, Relabel, Term, ValidId, object, utils};
3use contextual::{IntoRefWithContext, WithContext};
4use derive_where::derive_where;
5use iri_rs::IriBuf;
6use jsonld_syntax::{IntoJson, IntoJsonWithContext, Keyword};
7use rdfx::{
8    BlankIdBuf,
9    LocalGenerator,
10    vocabulary::{Vocabulary, VocabularyMut},
11};
12use std::{
13    convert::TryFrom,
14    hash::{Hash, Hasher},
15};
16
17/// Multiset used to hold the several values of a property.
18pub mod multiset;
19/// Properties of a node object.
20pub mod properties;
21/// Reverse properties of a node object.
22pub mod reverse_properties;
23
24pub use multiset::Multiset;
25pub use properties::Properties;
26pub use reverse_properties::ReverseProperties;
27
28/// Type alias for the `@graph` entry of a node.
29///
30/// Switched from `IndexSet` to `Vec` because all writes are insertion-only
31/// and reads only iterate (no `contains`, no hash-based lookup). The original
32/// `IndexSet` paid for `Hash` on each insert — and that hash recursively walked
33/// the entire `IndexedObject` tree (Properties → Multiset → `IndexedObject`…),
34/// which dominates expansion of nested or repeated-term documents.
35///
36/// JSON-LD does not require dedup of identical sub-objects in `@graph` /
37/// `@included`, so simple `Vec::push` is correct (and the conformance suite
38/// agrees).
39pub type Graph<T, B> = Vec<IndexedObject<T, B>>;
40
41/// Node objects included alongside another through `@included`.
42pub type Included<T, B> = Vec<IndexedNode<T, B>>;
43
44/// Node object carrying an optional `@index`.
45pub type IndexedNode<T = IriBuf, B = BlankIdBuf> = Indexed<Node<T, B>>;
46
47/// Node object.
48///
49/// A node object represents zero or more properties of a node in the graph serialized by a JSON-LD document.
50/// A node is defined by its identifier (`@id` field), types, properties and reverse properties.
51/// In addition, a node may represent a graph (`@graph` field) and include
52/// other nodes (`@included` field).
53#[derive(Debug, Clone)]
54pub struct Node<T = IriBuf, B = BlankIdBuf> {
55    /// Identifier.
56    ///
57    /// This is the `@id` field.
58    pub id: Option<Id<T, B>>,
59
60    /// Types.
61    ///
62    /// This is the `@type` field.
63    pub types: Option<Vec<Id<T, B>>>,
64
65    /// Associated graph.
66    ///
67    /// This is the `@graph` field.
68    pub graph: Option<Graph<T, B>>,
69
70    /// Included nodes.
71    ///
72    /// This is the `@included` field.
73    pub included: Option<Included<T, B>>,
74
75    /// Properties.
76    ///
77    /// Any non-keyword field.
78    pub properties: Properties<T, B>,
79
80    /// Reverse properties.
81    ///
82    /// This is the `@reverse` field.
83    pub reverse_properties: Option<ReverseProperties<T, B>>,
84}
85
86impl<T, B> Default for Node<T, B> {
87    #[inline(always)]
88    fn default() -> Self {
89        Self::new()
90    }
91}
92
93impl<T, B> Node<T, B> {
94    /// Creates a new empty node.
95    #[inline(always)]
96    #[must_use]
97    pub fn new() -> Self {
98        Self {
99            id: None,
100            types: None,
101            graph: None,
102            included: None,
103            properties: Properties::new(),
104            reverse_properties: None,
105        }
106    }
107
108    /// Creates a new empty node with the given id.
109    #[inline(always)]
110    pub fn with_id(id: Id<T, B>) -> Self {
111        Self {
112            id: Some(id),
113            types: None,
114            graph: None,
115            included: None,
116            properties: Properties::new(),
117            reverse_properties: None,
118        }
119    }
120
121    /// Creates a new graph node.
122    pub fn new_graph(id: Id<T, B>, graph: Graph<T, B>) -> Self {
123        Self {
124            id: Some(id),
125            types: None,
126            graph: Some(graph),
127            included: None,
128            properties: Properties::new(),
129            reverse_properties: None,
130        }
131    }
132
133    /// Returns a mutable reference to the reverse properties of the node.
134    ///
135    /// If no `@reverse` entry is present, one is created.
136    #[inline(always)]
137    pub fn reverse_properties_mut_or_default(&mut self) -> &mut ReverseProperties<T, B> {
138        self.reverse_properties.get_or_insert_with(ReverseProperties::default)
139    }
140
141    /// Returns a mutable reference to the included nodes.
142    ///
143    /// If no `@included` entry is present, one is created.
144    #[inline(always)]
145    pub fn included_mut_or_default(&mut self) -> &mut Included<T, B> {
146        self.included.get_or_insert_with(Included::default)
147    }
148
149    /// Assigns an identifier to this node and every other node included in this
150    /// one using the given `generator`.
151    ///
152    /// # Errors
153    ///
154    /// Returns an error when the generator runs out of identifiers.
155    pub fn identify_all_with<V: VocabularyMut<Iri = T, BlankId = B>, G: LocalGenerator>(
156        &mut self,
157        vocabulary: &mut V,
158        generator: &mut G,
159    ) -> Result<(), crate::id::GeneratedIdError>
160    where
161        T: Eq + Hash,
162        B: Eq + Hash,
163    {
164        if self.id.is_none() {
165            self.id = Some(crate::id::generator_next_id(vocabulary, generator)?.into());
166        }
167
168        if let Some(graph) = self.graph_mut() {
169            for o in graph.iter_mut() {
170                o.identify_all_with(vocabulary, generator)?;
171            }
172        }
173
174        if let Some(included) = self.included_mut() {
175            for n in included.iter_mut() {
176                n.identify_all_with(vocabulary, generator)?;
177            }
178        }
179
180        for (_, objects) in self.properties_mut() {
181            for object in objects {
182                object.identify_all_with(vocabulary, generator)?;
183            }
184        }
185
186        if let Some(reverse_properties) = self.reverse_properties_mut() {
187            for (_, nodes) in reverse_properties.iter_mut() {
188                for node in nodes {
189                    node.identify_all_with(vocabulary, generator)?;
190                }
191            }
192        }
193
194        Ok(())
195    }
196
197    /// Assigns an identifier to this node and every other node included in this one using the given `generator`.
198    ///
199    /// # Errors
200    ///
201    /// Returns an error when the generator runs out of identifiers.
202    pub fn identify_all<G: LocalGenerator>(&mut self, generator: &mut G) -> Result<(), crate::id::GeneratedIdError>
203    where
204        T: Eq + Hash,
205        B: Eq + Hash,
206        (): Vocabulary<Iri = T, BlankId = B>,
207    {
208        self.identify_all_with(&mut (), generator)
209    }
210
211    /// Puts every literal of the node into canonical form, using the given
212    /// `buffer` to render numbers.
213    pub fn canonicalize_with(&mut self, buffer: &mut ryu_js::Buffer) {
214        for (_, objects) in self.properties_mut() {
215            for object in objects {
216                object.canonicalize_with(buffer);
217            }
218        }
219
220        if let Some(reverse_properties) = self.reverse_properties_mut() {
221            for (_, nodes) in reverse_properties.iter_mut() {
222                for node in nodes {
223                    node.canonicalize_with(buffer);
224                }
225            }
226        }
227    }
228
229    /// Puts every literal of the node into canonical form.
230    pub fn canonicalize(&mut self) {
231        let mut buffer = ryu_js::Buffer::new();
232        self.canonicalize_with(&mut buffer);
233    }
234
235    /// Returns the node's identifier as an IRI, if the node has one and it
236    /// is an IRI.
237    #[inline(always)]
238    pub fn as_iri(&self) -> Option<&T> {
239        if let Some(id) = &self.id { id.as_iri() } else { None }
240    }
241
242    /// Returns the node's identifier as a string slice.
243    ///
244    /// Returns `None` if the node has no `@id` field.
245    #[inline(always)]
246    pub fn as_str(&self) -> Option<&str>
247    where
248        T: AsRef<str>,
249    {
250        match self.as_iri() {
251            Some(iri) => Some(iri.as_ref()),
252            None => None,
253        }
254    }
255
256    /// Returns the types of the node, or an empty slice if it has no `@type`
257    /// entry.
258    #[inline(always)]
259    pub fn types(&self) -> &[Id<T, B>] {
260        match self.types.as_ref() {
261            Some(entry) => entry,
262            None => &[],
263        }
264    }
265
266    /// Mutably borrows the types of the node, or an empty slice if it has no
267    /// `@type` entry.
268    #[inline(always)]
269    pub fn types_mut(&mut self) -> &mut [Id<T, B>] {
270        match self.types.as_mut() {
271            Some(entry) => entry,
272            None => &mut [],
273        }
274    }
275
276    /// Mutably borrows the types of this node, inserting an empty list if it
277    /// has none.
278    pub fn types_mut_or_default(&mut self) -> &mut Vec<Id<T, B>> {
279        self.types.get_or_insert_with(Vec::new)
280    }
281
282    /// Mutably borrows the types of this node, inserting `value` if it has
283    /// none.
284    pub fn types_mut_or_insert(&mut self, value: Vec<Id<T, B>>) -> &mut Vec<Id<T, B>> {
285        self.types.get_or_insert(value)
286    }
287
288    /// Mutably borrows the types of this node, inserting the result of `f` if
289    /// it has none.
290    pub fn types_mut_or_insert_with(&mut self, f: impl FnOnce() -> Vec<Id<T, B>>) -> &mut Vec<Id<T, B>> {
291        self.types.get_or_insert_with(f)
292    }
293
294    /// Checks if the node has the given type.
295    #[inline]
296    pub fn has_type<U>(&self, ty: &U) -> bool
297    where
298        Id<T, B>: PartialEq<U>,
299    {
300        for self_ty in self.types() {
301            if self_ty == ty {
302                return true;
303            }
304        }
305
306        false
307    }
308
309    /// Tests if the node is empty.
310    ///
311    /// It is empty if every field other than `@id` is empty.
312    #[inline]
313    pub fn is_empty(&self) -> bool {
314        self.types.is_none() && self.graph.is_none() && self.included.is_none() && self.properties.is_empty() && self.reverse_properties.is_none()
315    }
316
317    /// Tests if the node is a graph object (has a `@graph` field, and
318    /// optionally an `@id` field). A node object with a `@graph` entry is
319    /// not considered a graph object if it includes any entry other than
320    /// `@id`.
321    #[inline]
322    pub fn is_graph(&self) -> bool {
323        self.graph.is_some() && self.types.is_none() && self.included.is_none() && self.properties.is_empty() && self.reverse_properties.is_none()
324    }
325
326    /// Tests if the node is a simple graph object (a graph object without `@id` field)
327    #[inline(always)]
328    pub fn is_simple_graph(&self) -> bool {
329        self.id.is_none() && self.is_graph()
330    }
331
332    /// Returns the node objects of the `@graph` entry, if the node has one.
333    ///
334    /// Note that having a `@graph` entry is necessary but not sufficient for
335    /// the node to be a graph object; see [`is_graph`](Self::is_graph).
336    #[inline(always)]
337    pub fn graph(&self) -> Option<&Graph<T, B>> {
338        self.graph.as_ref()
339    }
340
341    /// Mutably borrows the node objects of the `@graph` entry, if the node
342    /// has one.
343    #[inline(always)]
344    pub fn graph_mut(&mut self) -> Option<&mut Graph<T, B>> {
345        self.graph.as_mut()
346    }
347
348    /// Returns the node objects of the `@graph` entry, if the node has one.
349    ///
350    /// Alias for [`graph`](Self::graph).
351    #[inline(always)]
352    pub fn graph_entry(&self) -> Option<&Graph<T, B>> {
353        self.graph.as_ref()
354    }
355
356    /// Mutably borrows the node objects of the `@graph` entry, if the node
357    /// has one.
358    ///
359    /// Alias for [`graph_mut`](Self::graph_mut).
360    #[inline(always)]
361    pub fn graph_entry_mut(&mut self) -> Option<&mut Graph<T, B>> {
362        self.graph.as_mut()
363    }
364
365    /// Sets the `@graph` entry of the node, or removes it when given `None`.
366    #[inline(always)]
367    pub fn set_graph_entry(&mut self, graph: Option<Graph<T, B>>) {
368        self.graph = graph;
369    }
370
371    /// Returns the set of nodes included by this node.
372    ///
373    /// This corresponds to the `@included` field in the JSON representation.
374    #[inline(always)]
375    pub fn included_entry(&self) -> Option<&Included<T, B>> {
376        self.included.as_ref()
377    }
378
379    /// Returns the mutable set of nodes included by this node.
380    ///
381    /// This corresponds to the `@included` field in the JSON representation.
382    #[inline(always)]
383    pub fn included_entry_mut(&mut self) -> Option<&mut Included<T, B>> {
384        self.included.as_mut()
385    }
386
387    /// Returns a reference to the set of `@included` nodes.
388    pub fn included(&self) -> Option<&Included<T, B>> {
389        self.included.as_ref()
390    }
391
392    /// Returns a mutable reference to the set of `@included` nodes.
393    pub fn included_mut(&mut self) -> Option<&mut Included<T, B>> {
394        self.included.as_mut()
395    }
396
397    /// Sets the `@included` entry of the node, or removes it when given
398    /// `None`.
399    #[inline(always)]
400    pub fn set_included(&mut self, included: Option<Included<T, B>>) {
401        self.included = included;
402    }
403
404    /// Returns a reference to the properties of the node.
405    #[inline(always)]
406    pub fn properties(&self) -> &Properties<T, B> {
407        &self.properties
408    }
409
410    /// Returns a mutable reference to the properties of the node.
411    #[inline(always)]
412    pub fn properties_mut(&mut self) -> &mut Properties<T, B> {
413        &mut self.properties
414    }
415
416    /// Returns a reference to the reverse properties of the node, if it has
417    /// a `@reverse` entry.
418    #[inline(always)]
419    pub fn reverse_properties(&self) -> Option<&ReverseProperties<T, B>> {
420        self.reverse_properties.as_ref()
421    }
422
423    /// Returns a reference to the reverse properties of the node, if it has
424    /// a `@reverse` entry.
425    #[inline(always)]
426    pub fn reverse_properties_entry(&self) -> Option<&ReverseProperties<T, B>> {
427        self.reverse_properties.as_ref()
428    }
429
430    /// Returns a mutable reference to the reverse properties of the node, if
431    /// it has a `@reverse` entry.
432    #[inline(always)]
433    pub fn reverse_properties_mut(&mut self) -> Option<&mut ReverseProperties<T, B>> {
434        self.reverse_properties.as_mut()
435    }
436
437    /// Sets the reverse properties of this `Node`.
438    pub fn set_reverse_properties(&mut self, reverse_properties: Option<ReverseProperties<T, B>>) {
439        self.reverse_properties = reverse_properties;
440    }
441
442    /// Tests if the node is an unnamed graph object.
443    ///
444    /// Returns `true` if the only field of the object is a `@graph` field,
445    /// `false` otherwise.
446    #[inline]
447    pub fn is_unnamed_graph(&self) -> bool {
448        self.graph.is_some()
449            && self.id.is_none()
450            && self.types.is_none()
451            && self.included.is_none()
452            && self.properties.is_empty()
453            && self.reverse_properties.is_none()
454    }
455
456    /// Returns the node as an unnamed graph, if it is one.
457    ///
458    /// The unnamed graph is returned as a set of indexed objects.
459    /// Fails and returns itself if the node is *not* an unnamed graph.
460    ///
461    /// # Errors
462    ///
463    /// Returns `self` unchanged when the object is not a graph object, or is a named graph.
464    #[inline(always)]
465    pub fn into_unnamed_graph(self: Box<Self>) -> Result<Graph<T, B>, Box<Self>> {
466        if self.is_unnamed_graph() {
467            // SAFETY: `is_unnamed_graph()` implies `self.graph` is `Some`.
468            Ok(unsafe { self.graph.unwrap_unchecked() })
469        } else {
470            Err(self)
471        }
472    }
473
474    /// Returns an iterator that visits every fragment of the node: the node
475    /// itself and, recursively, everything it contains.
476    pub fn traverse(&self) -> Traverse<'_, T, B> {
477        Traverse::new(Some(super::FragmentRef::Node(self)))
478    }
479
480    #[inline(always)]
481    /// Counts the fragments of the node matching the given predicate.
482    pub fn count(&self, f: impl FnMut(&super::FragmentRef<T, B>) -> bool) -> usize {
483        self.traverse().filter(f).count()
484    }
485
486    /// Returns an iterator over the entries of the JSON representation of
487    /// the node.
488    pub fn entries(&self) -> Entries<'_, T, B> {
489        Entries {
490            id: self.id.as_ref(),
491            type_: self.types.as_deref(),
492            graph: self.graph.as_ref(),
493            included: self.included.as_ref(),
494            reverse: self.reverse_properties.as_ref(),
495            properties: self.properties.iter(),
496        }
497    }
498
499    /// Rewrites every IRI and identifier of the node (recursively) with the
500    /// given functions.
501    pub fn map_ids<U, C>(self, mut map_iri: impl FnMut(T) -> U, mut map_id: impl FnMut(Id<T, B>) -> Id<U, C>) -> Node<U, C>
502    where
503        U: Eq + Hash,
504        C: Eq + Hash,
505    {
506        self.map_ids_with(&mut map_iri, &mut map_id)
507    }
508
509    pub(crate) fn map_ids_with<U, C>(self, map_iri: &mut impl FnMut(T) -> U, map_id: &mut impl FnMut(Id<T, B>) -> Id<U, C>) -> Node<U, C>
510    where
511        U: Eq + Hash,
512        C: Eq + Hash,
513    {
514        Node {
515            id: self.id.map(&mut *map_id),
516            types: self.types.map(|t| t.into_iter().map(&mut *map_id).collect()),
517            graph: self
518                .graph
519                .map(|g| g.into_iter().map(|o| o.map_inner(|o| o.map_ids_with(map_iri, map_id))).collect()),
520            included: self
521                .included
522                .map(|i| i.into_iter().map(|o| o.map_inner(|o| o.map_ids_with(map_iri, map_id))).collect()),
523            properties: self
524                .properties
525                .into_iter()
526                .map(|(id, values)| {
527                    (
528                        map_id(id),
529                        values.into_iter().map(|o| o.map_inner(|o| o.map_ids_with(map_iri, map_id))).collect::<Vec<_>>(),
530                    )
531                })
532                .collect(),
533            reverse_properties: self.reverse_properties.map(|r| {
534                r.into_iter()
535                    .map(|(id, values)| {
536                        (
537                            map_id(id),
538                            values.into_iter().map(|o| o.map_inner(|o| o.map_ids_with(map_iri, map_id))).collect::<Vec<_>>(),
539                        )
540                    })
541                    .collect()
542            }),
543        }
544    }
545}
546
547impl<T: Eq + Hash, B: Eq + Hash> Node<T, B> {
548    /// Checks if the node object has the given term as key.
549    ///
550    /// # Example
551    /// ```
552    /// # use jsonld_syntax::Keyword;
553    /// # use jsonld_core::Term;
554    /// # let node: jsonld_core::Node = jsonld_core::Node::new();
555    ///
556    /// // Checks if the JSON object representation of the node has an `@id` key.
557    /// if node.has_key(&Term::Keyword(Keyword::Id)) {
558    ///   // ...
559    /// }
560    /// ```
561    #[inline(always)]
562    pub fn has_key(&self, key: &Term<T, B>) -> bool {
563        match key {
564            Term::Keyword(Keyword::Id) => self.id.is_some(),
565            Term::Keyword(Keyword::Type) => self.types.is_some(),
566            Term::Keyword(Keyword::Graph) => self.graph.is_some(),
567            Term::Keyword(Keyword::Included) => self.included.is_some(),
568            Term::Keyword(Keyword::Reverse) => self.reverse_properties.is_some(),
569            Term::Id(prop) => self.properties.contains(prop),
570            _ => false,
571        }
572    }
573
574    /// Returns all the objects associated with the node through the given
575    /// property.
576    #[inline(always)]
577    pub fn get<'a, Q: ?Sized + Hash + indexmap::Equivalent<Id<T, B>>>(&self, prop: &Q) -> Objects<'_, T, B>
578    where
579        T: 'a,
580    {
581        self.properties.get(prop)
582    }
583
584    /// Returns one of the objects associated with the node through the given
585    /// property.
586    ///
587    /// If multiple objects are attached to the node with this property,
588    /// there is no guarantee on which object is returned.
589    #[inline(always)]
590    pub fn get_any<'a, Q: ?Sized + Hash + indexmap::Equivalent<Id<T, B>>>(&self, prop: &Q) -> Option<&IndexedObject<T, B>>
591    where
592        T: 'a,
593    {
594        self.properties.get_any(prop)
595    }
596
597    /// Associates the given object with the node through the given property.
598    #[inline(always)]
599    pub fn insert(&mut self, prop: Id<T, B>, value: IndexedObject<T, B>) {
600        self.properties.insert(prop, value);
601    }
602
603    /// Associates all the given objects with the node through the given
604    /// property.
605    ///
606    /// If objects are already associated with the property, the new ones are
607    /// appended to them. Duplicate objects are not removed.
608    #[inline(always)]
609    pub fn insert_all<Objects: Iterator<Item = IndexedObject<T, B>>>(&mut self, prop: Id<T, B>, values: Objects) {
610        self.properties.insert_all(prop, values);
611    }
612
613    /// Mutably borrows the reverse properties, inserting `props` if there are
614    /// none.
615    pub fn reverse_properties_or_insert(&mut self, props: ReverseProperties<T, B>) -> &mut ReverseProperties<T, B> {
616        self.reverse_properties.get_or_insert(props)
617    }
618
619    /// Mutably borrows the reverse properties, inserting an empty set if there
620    /// are none.
621    pub fn reverse_properties_or_default(&mut self) -> &mut ReverseProperties<T, B> {
622        self.reverse_properties.get_or_insert_with(ReverseProperties::default)
623    }
624
625    /// Mutably borrows the reverse properties, inserting the result of `f` if
626    /// there are none.
627    pub fn reverse_properties_or_insert_with(&mut self, f: impl FnOnce() -> ReverseProperties<T, B>) -> &mut ReverseProperties<T, B> {
628        self.reverse_properties.get_or_insert_with(f)
629    }
630
631    /// Equivalence operator.
632    ///
633    /// Equivalence differs from equality for anonymous objects: an anonymous
634    /// node object stands for an implicit, unlabeled blank node, so it is
635    /// never equivalent to anything.
636    pub fn equivalent(&self, other: &Self) -> bool {
637        if self.id.is_some() && other.id.is_some() { self == other } else { false }
638    }
639}
640
641impl<T, B> Relabel<T, B> for Node<T, B> {
642    fn relabel_with<N: VocabularyMut<Iri = T, BlankId = B>, G: LocalGenerator>(
643        &mut self,
644        vocabulary: &mut N,
645        generator: &mut G,
646        relabeling: &mut HashMap<B, ValidId<T, B>>,
647    ) -> Result<(), crate::id::GeneratedIdError>
648    where
649        T: Clone + Eq + Hash,
650        B: Clone + Eq + Hash,
651    {
652        self.id = match self.id.take() {
653            Some(Id::Valid(ValidId::Blank(b))) => {
654                let value = match relabeling.entry(b) {
655                    hashbrown::hash_map::Entry::Occupied(o) => o.get().clone(),
656                    hashbrown::hash_map::Entry::Vacant(v) => v.insert(crate::id::generator_next_id(vocabulary, generator)?).clone(),
657                };
658                Some(value.into())
659            }
660            None => {
661                let value = crate::id::generator_next_id(vocabulary, generator)?;
662                Some(value.into())
663            }
664            id => id,
665        };
666
667        for ty in self.types_mut() {
668            if let Some(b) = ty.as_blank().cloned() {
669                let value = match relabeling.entry(b) {
670                    hashbrown::hash_map::Entry::Occupied(o) => o.get().clone(),
671                    hashbrown::hash_map::Entry::Vacant(v) => v.insert(crate::id::generator_next_id(vocabulary, generator)?).clone(),
672                };
673                *ty = value.into();
674            }
675        }
676
677        if let Some(graph) = self.graph_mut() {
678            for o in graph.iter_mut() {
679                o.relabel_with(vocabulary, generator, relabeling)?;
680            }
681        }
682
683        if let Some(included) = self.included_mut() {
684            for n in included.iter_mut() {
685                n.relabel_with(vocabulary, generator, relabeling)?;
686            }
687        }
688
689        // "If property is a blank node identifier, replace it with a newly
690        // generated blank node identifier": property keys are relabeled from
691        // the same map as node identifiers (`toRdf#t0118`). Keys are rewritten
692        // in place, in insertion order, so the generator sees each blank node
693        // in document order.
694        if !self.properties.is_empty() {
695            let properties = std::mem::take(&mut self.properties);
696            for (property, mut objects) in properties {
697                let property = match property {
698                    Id::Valid(ValidId::Blank(b)) => {
699                        let value = match relabeling.entry(b) {
700                            hashbrown::hash_map::Entry::Occupied(o) => o.get().clone(),
701                            hashbrown::hash_map::Entry::Vacant(v) => v.insert(crate::id::generator_next_id(vocabulary, generator)?).clone(),
702                        };
703                        value.into()
704                    }
705                    property => property,
706                };
707
708                for object in &mut objects {
709                    object.relabel_with(vocabulary, generator, relabeling)?;
710                }
711
712                self.properties.set(property, objects);
713            }
714        }
715
716        if let Some(reverse_properties) = self.reverse_properties_mut() {
717            for (_, nodes) in reverse_properties.iter_mut() {
718                for node in nodes {
719                    node.relabel_with(vocabulary, generator, relabeling)?;
720                }
721            }
722        }
723
724        Ok(())
725    }
726}
727
728impl<T: Eq + Hash, B: Eq + Hash> PartialEq for Node<T, B> {
729    fn eq(&self, other: &Self) -> bool {
730        // `@graph` and `@included` are sets of node objects: their order is not
731        // significant (only `@list` is ordered). This matches `Hash`, which
732        // already hashes both with `hash_set_opt`.
733        self.id.eq(&other.id)
734            && multiset::compare_unordered_opt(self.types.as_deref(), other.types.as_deref())
735            && multiset::compare_unordered_opt(self.graph.as_deref(), other.graph.as_deref())
736            && multiset::compare_unordered_opt(self.included.as_deref(), other.included.as_deref())
737            && self.properties.eq(&other.properties)
738            && self.reverse_properties.eq(&other.reverse_properties)
739    }
740}
741
742impl<T: Eq + Hash, B: Eq + Hash> Eq for Node<T, B> {}
743
744impl<T, B> Indexed<Node<T, B>> {
745    /// Returns an iterator over the entries of the JSON representation of
746    /// the node, including its `@index` entry if any.
747    pub fn entries(&self) -> IndexedEntries<'_, T, B> {
748        IndexedEntries {
749            index: self.index(),
750            inner: self.inner().entries(),
751        }
752    }
753}
754
755impl<T: Eq + Hash, B: Eq + Hash> Indexed<Node<T, B>> {
756    /// Checks whether the two indexed nodes are equivalent: same `@index`
757    /// and [equivalent](Node::equivalent) inner nodes.
758    pub fn equivalent(&self, other: &Self) -> bool {
759        self.index() == other.index() && self.inner().equivalent(other.inner())
760    }
761}
762
763// `bound(false)`: every variant payload is a shared reference, a slice, or
764// another unconditionally-`Copy` borrow type, so the impls hold for any `T`/`B`.
765// A plain `derive` would instead add a bound per field type,
766// making the impl conditional and breaking the `&self` methods that consume
767// `self` by copy.
768#[derive(PartialEq, Eq)]
769#[derive_where(Clone, Copy)]
770/// Key of a node object entry.
771pub enum EntryKeyRef<'a, T, B> {
772    /// The `@id` entry, identifying the node or mapping the term to an IRI.
773    Id,
774    /// The `@type` entry, giving the type of the node or the values.
775    Type,
776    /// The `@graph` entry, holding the node objects of a named graph.
777    Graph,
778    /// The `@included` entry, holding node objects included alongside this one.
779    Included,
780    /// The `@reverse` entry, mapping the term to a reverse property.
781    Reverse,
782    /// A property of a node object.
783    Property(&'a Id<T, B>),
784}
785
786impl<'a, T, B> EntryKeyRef<'a, T, B> {
787    /// Returns the JSON-LD keyword this key stands for, if any.
788    #[must_use]
789    pub fn into_keyword(self) -> Option<Keyword> {
790        match self {
791            Self::Id => Some(Keyword::Id),
792            Self::Type => Some(Keyword::Type),
793            Self::Graph => Some(Keyword::Graph),
794            Self::Included => Some(Keyword::Included),
795            Self::Reverse => Some(Keyword::Reverse),
796            Self::Property(_) => None,
797        }
798    }
799
800    /// Returns the JSON-LD keyword this key stands for, if any.
801    #[must_use]
802    pub fn as_keyword(&self) -> Option<Keyword> {
803        self.into_keyword()
804    }
805
806    /// Returns the key as a string slice.
807    #[must_use]
808    pub fn into_str(self) -> &'a str
809    where
810        T: AsRef<str>,
811        B: AsRef<str>,
812    {
813        match self {
814            Self::Id => "@id",
815            Self::Type => "@type",
816            Self::Graph => "@graph",
817            Self::Included => "@included",
818            Self::Reverse => "@reverse",
819            Self::Property(p) => p.as_str(),
820        }
821    }
822
823    /// Returns this value as a string slice.
824    #[must_use]
825    pub fn as_str(&self) -> &'a str
826    where
827        T: AsRef<str>,
828        B: AsRef<str>,
829    {
830        self.into_str()
831    }
832}
833
834impl<'a, T, B, N: Vocabulary<Iri = T, BlankId = B>> IntoRefWithContext<'a, str, N> for EntryKeyRef<'a, T, B> {
835    fn into_ref_with(self, vocabulary: &'a N) -> &'a str {
836        match self {
837            EntryKeyRef::Id => "@id",
838            EntryKeyRef::Type => "@type",
839            EntryKeyRef::Graph => "@graph",
840            EntryKeyRef::Included => "@included",
841            EntryKeyRef::Reverse => "@reverse",
842            EntryKeyRef::Property(p) => p.with(vocabulary).as_str(),
843        }
844    }
845}
846
847#[derive_where(Clone, Copy)]
848/// Value of a node object entry.
849pub enum EntryValueRef<'a, T, B> {
850    /// The `@id` entry, identifying the node or mapping the term to an IRI.
851    Id(&'a Id<T, B>),
852    /// The `@type` entry, giving the type of the node or the values.
853    Type(&'a [Id<T, B>]),
854    /// The `@graph` entry, holding the node objects of a named graph.
855    Graph(&'a Graph<T, B>),
856    /// The `@included` entry, holding node objects included alongside this one.
857    Included(&'a Included<T, B>),
858    /// The `@reverse` entry, mapping the term to a reverse property.
859    Reverse(&'a ReverseProperties<T, B>),
860    /// A property of a node object.
861    Property(&'a [IndexedObject<T, B>]),
862}
863
864impl<'a, T, B> EntryValueRef<'a, T, B> {
865    /// Checks whether this entry value renders as a JSON array.
866    #[must_use]
867    pub fn is_json_array(&self) -> bool {
868        matches!(self, Self::Type(_) | Self::Graph(_) | Self::Included(_) | Self::Property(_))
869    }
870
871    /// Checks whether this entry value renders as a JSON object.
872    #[must_use]
873    pub fn is_json_object(&self) -> bool {
874        matches!(self, Self::Reverse(_))
875    }
876
877    fn sub_fragments(&self) -> SubFragments<'a, T, B> {
878        match self {
879            Self::Type(l) => SubFragments::Type(l.iter()),
880            Self::Graph(g) => SubFragments::Graph(g.iter()),
881            Self::Included(i) => SubFragments::Included(i.iter()),
882            Self::Reverse(r) => SubFragments::Reverse(r.iter()),
883            Self::Property(p) => SubFragments::Property(p.iter()),
884            Self::Id(_) => SubFragments::None,
885        }
886    }
887}
888
889#[derive_where(Clone, Copy)]
890/// Entry of a node object, key and value together.
891pub enum EntryRef<'a, T, B> {
892    /// The `@id` entry, identifying the node or mapping the term to an IRI.
893    Id(&'a Id<T, B>),
894    /// The `@type` entry, giving the type of the node or the values.
895    Type(&'a [Id<T, B>]),
896    /// The `@graph` entry, holding the node objects of a named graph.
897    Graph(&'a Graph<T, B>),
898    /// The `@included` entry, holding node objects included alongside this one.
899    Included(&'a Included<T, B>),
900    /// The `@reverse` entry, mapping the term to a reverse property.
901    Reverse(&'a ReverseProperties<T, B>),
902    /// A property of a node object.
903    Property(&'a Id<T, B>, &'a [IndexedObject<T, B>]),
904}
905
906impl<'a, T, B> EntryRef<'a, T, B> {
907    /// Consumes this `EntryRef`, returning its key.
908    #[must_use]
909    pub fn into_key(self) -> EntryKeyRef<'a, T, B> {
910        match self {
911            Self::Id(_) => EntryKeyRef::Id,
912            Self::Type(_) => EntryKeyRef::Type,
913            Self::Graph(_) => EntryKeyRef::Graph,
914            Self::Included(_) => EntryKeyRef::Included,
915            Self::Reverse(_) => EntryKeyRef::Reverse,
916            Self::Property(k, _) => EntryKeyRef::Property(k),
917        }
918    }
919
920    /// Returns the key of this `EntryRef`.
921    #[must_use]
922    pub fn key(&self) -> EntryKeyRef<'a, T, B> {
923        self.into_key()
924    }
925
926    /// Consumes this `EntryRef`, returning its value.
927    #[must_use]
928    pub fn into_value(self) -> EntryValueRef<'a, T, B> {
929        match self {
930            Self::Id(v) => EntryValueRef::Id(v),
931            Self::Type(v) => EntryValueRef::Type(v),
932            Self::Graph(v) => EntryValueRef::Graph(v),
933            Self::Included(v) => EntryValueRef::Included(v),
934            Self::Reverse(v) => EntryValueRef::Reverse(v),
935            Self::Property(_, v) => EntryValueRef::Property(v),
936        }
937    }
938
939    /// Returns the value of this `EntryRef`.
940    #[must_use]
941    pub fn value(&self) -> EntryValueRef<'a, T, B> {
942        self.into_value()
943    }
944
945    /// Consumes this `EntryRef`, returning its key and value.
946    #[must_use]
947    pub fn into_key_value(self) -> (EntryKeyRef<'a, T, B>, EntryValueRef<'a, T, B>) {
948        match self {
949            Self::Id(v) => (EntryKeyRef::Id, EntryValueRef::Id(v)),
950            Self::Type(v) => (EntryKeyRef::Type, EntryValueRef::Type(v)),
951            Self::Graph(v) => (EntryKeyRef::Graph, EntryValueRef::Graph(v)),
952            Self::Included(v) => (EntryKeyRef::Included, EntryValueRef::Included(v)),
953            Self::Reverse(v) => (EntryKeyRef::Reverse, EntryValueRef::Reverse(v)),
954            Self::Property(k, v) => (EntryKeyRef::Property(k), EntryValueRef::Property(v)),
955        }
956    }
957
958    /// Returns the key and value of this entry.
959    #[must_use]
960    pub fn as_key_value(&self) -> (EntryKeyRef<'a, T, B>, EntryValueRef<'a, T, B>) {
961        match self {
962            Self::Id(v) => (EntryKeyRef::Id, EntryValueRef::Id(*v)),
963            Self::Type(v) => (EntryKeyRef::Type, EntryValueRef::Type(v)),
964            Self::Graph(v) => (EntryKeyRef::Graph, EntryValueRef::Graph(*v)),
965            Self::Included(v) => (EntryKeyRef::Included, EntryValueRef::Included(*v)),
966            Self::Reverse(v) => (EntryKeyRef::Reverse, EntryValueRef::Reverse(*v)),
967            Self::Property(k, v) => (EntryKeyRef::Property(*k), EntryValueRef::Property(v)),
968        }
969    }
970}
971
972#[derive_where(Clone)]
973/// Iterator over the entries of a node object.
974pub struct Entries<'a, T, B> {
975    id: Option<&'a Id<T, B>>,
976    type_: Option<&'a [Id<T, B>]>,
977    graph: Option<&'a Graph<T, B>>,
978    included: Option<&'a Included<T, B>>,
979    reverse: Option<&'a ReverseProperties<T, B>>,
980    properties: properties::Iter<'a, T, B>,
981}
982
983impl<'a, T, B> Iterator for Entries<'a, T, B> {
984    type Item = EntryRef<'a, T, B>;
985
986    fn size_hint(&self) -> (usize, Option<usize>) {
987        let mut len = self.properties.len();
988
989        if self.id.is_some() {
990            len += 1;
991        }
992
993        if self.type_.is_some() {
994            len += 1;
995        }
996
997        if self.graph.is_some() {
998            len += 1;
999        }
1000
1001        if self.included.is_some() {
1002            len += 1;
1003        }
1004
1005        if self.reverse.is_some() {
1006            len += 1;
1007        }
1008
1009        (len, Some(len))
1010    }
1011
1012    fn next(&mut self) -> Option<Self::Item> {
1013        self.id.take().map(EntryRef::Id).or_else(|| {
1014            self.type_.take().map(EntryRef::Type).or_else(|| {
1015                self.graph.take().map(EntryRef::Graph).or_else(|| {
1016                    self.included.take().map(EntryRef::Included).or_else(|| {
1017                        self.reverse
1018                            .take()
1019                            .map(EntryRef::Reverse)
1020                            .or_else(|| self.properties.next().map(|(k, v)| EntryRef::Property(k, v)))
1021                    })
1022                })
1023            })
1024        })
1025    }
1026}
1027
1028impl<T, B> ExactSizeIterator for Entries<'_, T, B> {}
1029
1030#[derive_where(Clone)]
1031/// Iterator over the entries of an indexed node object, `@index` included.
1032pub struct IndexedEntries<'a, T, B> {
1033    index: Option<&'a str>,
1034    inner: Entries<'a, T, B>,
1035}
1036
1037impl<'a, T, B> Iterator for IndexedEntries<'a, T, B> {
1038    type Item = IndexedEntryRef<'a, T, B>;
1039
1040    fn size_hint(&self) -> (usize, Option<usize>) {
1041        let len = self.inner.len() + usize::from(self.index.is_some());
1042        (len, Some(len))
1043    }
1044
1045    fn next(&mut self) -> Option<Self::Item> {
1046        self.index
1047            .take()
1048            .map(IndexedEntryRef::Index)
1049            .or_else(|| self.inner.next().map(IndexedEntryRef::Node))
1050    }
1051}
1052
1053impl<T, B> ExactSizeIterator for IndexedEntries<'_, T, B> {}
1054
1055#[derive(PartialEq, Eq)]
1056#[derive_where(Clone, Copy)]
1057/// Key of an indexed node object entry.
1058pub enum IndexedEntryKeyRef<'a, T, B> {
1059    /// The `@index` entry.
1060    Index,
1061    /// A node object.
1062    Node(EntryKeyRef<'a, T, B>),
1063}
1064
1065impl<'a, T, B> IndexedEntryKeyRef<'a, T, B> {
1066    /// Returns the JSON-LD keyword this key stands for, if any.
1067    #[must_use]
1068    pub fn into_keyword(self) -> Option<Keyword> {
1069        match self {
1070            Self::Index => Some(Keyword::Index),
1071            Self::Node(e) => e.into_keyword(),
1072        }
1073    }
1074
1075    /// Returns the JSON-LD keyword this key stands for, if any.
1076    #[must_use]
1077    pub fn as_keyword(&self) -> Option<Keyword> {
1078        self.into_keyword()
1079    }
1080
1081    /// Returns the key as a string slice.
1082    #[must_use]
1083    pub fn into_str(self) -> &'a str
1084    where
1085        T: AsRef<str>,
1086        B: AsRef<str>,
1087    {
1088        match self {
1089            Self::Index => "@index",
1090            Self::Node(e) => e.into_str(),
1091        }
1092    }
1093
1094    /// Returns this value as a string slice.
1095    #[must_use]
1096    pub fn as_str(&self) -> &'a str
1097    where
1098        T: AsRef<str>,
1099        B: AsRef<str>,
1100    {
1101        self.into_str()
1102    }
1103}
1104
1105impl<'a, T, B, N: Vocabulary<Iri = T, BlankId = B>> IntoRefWithContext<'a, str, N> for IndexedEntryKeyRef<'a, T, B> {
1106    fn into_ref_with(self, vocabulary: &'a N) -> &'a str {
1107        match self {
1108            IndexedEntryKeyRef::Index => "@index",
1109            IndexedEntryKeyRef::Node(e) => e.into_with(vocabulary).into_str(),
1110        }
1111    }
1112}
1113
1114#[derive_where(Clone, Copy)]
1115/// Value of an indexed node object entry.
1116pub enum IndexedEntryValueRef<'a, T, B> {
1117    /// The value of the `@index` entry.
1118    Index(&'a str),
1119    /// A node object.
1120    Node(EntryValueRef<'a, T, B>),
1121}
1122
1123#[derive_where(Clone, Copy)]
1124/// Entry of an indexed node object, key and value together.
1125pub enum IndexedEntryRef<'a, T, B> {
1126    /// The `@index` entry and its value.
1127    Index(&'a str),
1128    /// A node object.
1129    Node(EntryRef<'a, T, B>),
1130}
1131
1132impl<'a, T, B> IndexedEntryRef<'a, T, B> {
1133    /// Consumes this `IndexedEntryRef`, returning its key.
1134    #[must_use]
1135    pub fn into_key(self) -> IndexedEntryKeyRef<'a, T, B> {
1136        match self {
1137            Self::Index(_) => IndexedEntryKeyRef::Index,
1138            Self::Node(e) => IndexedEntryKeyRef::Node(e.key()),
1139        }
1140    }
1141
1142    /// Returns the key of this `IndexedEntryRef`.
1143    #[must_use]
1144    pub fn key(&self) -> IndexedEntryKeyRef<'a, T, B> {
1145        self.into_key()
1146    }
1147
1148    /// Consumes this `IndexedEntryRef`, returning its value.
1149    #[must_use]
1150    pub fn into_value(self) -> IndexedEntryValueRef<'a, T, B> {
1151        match self {
1152            Self::Index(v) => IndexedEntryValueRef::Index(v),
1153            Self::Node(e) => IndexedEntryValueRef::Node(e.value()),
1154        }
1155    }
1156
1157    /// Returns the value of this `IndexedEntryRef`.
1158    #[must_use]
1159    pub fn value(&self) -> IndexedEntryValueRef<'a, T, B> {
1160        self.into_value()
1161    }
1162
1163    /// Consumes this `IndexedEntryRef`, returning its key and value.
1164    #[must_use]
1165    pub fn into_key_value(self) -> (IndexedEntryKeyRef<'a, T, B>, IndexedEntryValueRef<'a, T, B>) {
1166        match self {
1167            Self::Index(v) => (IndexedEntryKeyRef::Index, IndexedEntryValueRef::Index(v)),
1168            Self::Node(e) => {
1169                let (k, v) = e.into_key_value();
1170                (IndexedEntryKeyRef::Node(k), IndexedEntryValueRef::Node(v))
1171            }
1172        }
1173    }
1174
1175    /// Returns the key and value of this entry.
1176    #[must_use]
1177    pub fn as_key_value(&self) -> (IndexedEntryKeyRef<'a, T, B>, IndexedEntryValueRef<'a, T, B>) {
1178        self.into_key_value()
1179    }
1180}
1181
1182/// Node object fragment reference.
1183pub enum FragmentRef<'a, T, B> {
1184    /// Node object entry.
1185    Entry(EntryRef<'a, T, B>),
1186
1187    /// Node object entry key.
1188    Key(EntryKeyRef<'a, T, B>),
1189
1190    /// Node object entry value.
1191    Value(EntryValueRef<'a, T, B>),
1192
1193    /// "@type" entry value fragment.
1194    TypeFragment(&'a Id<T, B>),
1195}
1196
1197impl<'a, T, B> FragmentRef<'a, T, B> {
1198    /// Returns the identifier this fragment stands for, if it is one.
1199    #[must_use]
1200    pub fn into_id(self) -> Option<&'a Id<T, B>> {
1201        match self {
1202            Self::Key(EntryKeyRef::Property(id)) => Some(id),
1203            Self::Value(EntryValueRef::Id(id)) => Some(id),
1204            Self::TypeFragment(ty) => Some(ty),
1205            _ => None,
1206        }
1207    }
1208
1209    /// Returns the identifier this fragment stands for, if it is one.
1210    #[must_use]
1211    pub fn as_id(&self) -> Option<&'a Id<T, B>> {
1212        match self {
1213            Self::Key(EntryKeyRef::Property(id)) => Some(id),
1214            Self::Value(EntryValueRef::Id(id)) => Some(id),
1215            Self::TypeFragment(ty) => Some(ty),
1216            _ => None,
1217        }
1218    }
1219
1220    /// Checks whether this fragment renders as a JSON array.
1221    #[must_use]
1222    pub fn is_json_array(&self) -> bool {
1223        match self {
1224            Self::Value(v) => v.is_json_array(),
1225            _ => false,
1226        }
1227    }
1228
1229    /// Checks whether this fragment renders as a JSON object.
1230    #[must_use]
1231    pub fn is_json_object(&self) -> bool {
1232        match self {
1233            Self::Value(v) => v.is_json_object(),
1234            _ => false,
1235        }
1236    }
1237
1238    /// Returns an iterator over the fragments directly contained in this one.
1239    #[must_use]
1240    pub fn sub_fragments(&self) -> SubFragments<'a, T, B> {
1241        match self {
1242            Self::Entry(e) => SubFragments::Entry(Some(e.key()), Some(e.value())),
1243            Self::Value(v) => v.sub_fragments(),
1244            _ => SubFragments::None,
1245        }
1246    }
1247}
1248
1249/// Iterator over the fragments directly held by a node object.
1250pub enum SubFragments<'a, T, B> {
1251    /// No value.
1252    None,
1253    /// An object entry.
1254    Entry(Option<EntryKeyRef<'a, T, B>>, Option<EntryValueRef<'a, T, B>>),
1255    /// The `@type` entry, giving the type of the node or the values.
1256    Type(std::slice::Iter<'a, Id<T, B>>),
1257    /// The `@graph` entry, holding the node objects of a named graph.
1258    Graph(std::slice::Iter<'a, IndexedObject<T, B>>),
1259    /// The `@included` entry, holding node objects included alongside this one.
1260    Included(std::slice::Iter<'a, IndexedNode<T, B>>),
1261    /// The `@reverse` entry, mapping the term to a reverse property.
1262    Reverse(reverse_properties::Iter<'a, T, B>),
1263    /// A property of a node object.
1264    Property(std::slice::Iter<'a, IndexedObject<T, B>>),
1265}
1266
1267impl<'a, T, B> Iterator for SubFragments<'a, T, B> {
1268    type Item = super::FragmentRef<'a, T, B>;
1269
1270    fn next(&mut self) -> Option<Self::Item> {
1271        match self {
1272            Self::None => None,
1273            Self::Entry(k, v) => k
1274                .take()
1275                .map(|k| super::FragmentRef::NodeFragment(FragmentRef::Key(k)))
1276                .or_else(|| v.take().map(|v| super::FragmentRef::NodeFragment(FragmentRef::Value(v)))),
1277            Self::Type(l) => l.next_back().map(|t| super::FragmentRef::NodeFragment(FragmentRef::TypeFragment(t))),
1278            Self::Graph(g) => g.next().map(|o| super::FragmentRef::IndexedObject(o)),
1279            Self::Included(i) => i.next().map(|n| super::FragmentRef::IndexedNode(n)),
1280            Self::Reverse(r) => r.next().map(|(_, n)| super::FragmentRef::IndexedNodeList(n)),
1281            Self::Property(o) => o.next().map(|o| super::FragmentRef::IndexedObject(o)),
1282        }
1283    }
1284}
1285
1286impl<T, B> object::Any<T, B> for Node<T, B> {
1287    #[inline(always)]
1288    fn as_ref(&self) -> object::Ref<'_, T, B> {
1289        object::Ref::Node(self)
1290    }
1291}
1292
1293impl<T, B> TryFrom<Object<T, B>> for Node<T, B> {
1294    type Error = Object<T, B>;
1295
1296    #[inline(always)]
1297    fn try_from(obj: Object<T, B>) -> Result<Node<T, B>, Object<T, B>> {
1298        match obj {
1299            Object::Node(node) => Ok(*node),
1300            obj => Err(obj),
1301        }
1302    }
1303}
1304
1305impl<T: Hash, B: Hash> Hash for Node<T, B> {
1306    #[inline]
1307    fn hash<H: Hasher>(&self, h: &mut H) {
1308        self.id.hash(h);
1309        utils::hash_set_opt(self.types.as_ref(), h);
1310        utils::hash_set_opt(self.graph.as_ref(), h);
1311        utils::hash_set_opt(self.included.as_ref(), h);
1312        self.properties.hash(h);
1313        self.reverse_properties.hash(h);
1314    }
1315}
1316
1317/// Iterator through indexed nodes.
1318pub struct Nodes<'a, T, B>(Option<std::slice::Iter<'a, IndexedNode<T, B>>>);
1319
1320impl<'a, T, B> Nodes<'a, T, B> {
1321    #[inline(always)]
1322    pub(crate) fn new(inner: Option<std::slice::Iter<'a, IndexedNode<T, B>>>) -> Self {
1323        Self(inner)
1324    }
1325}
1326
1327impl<'a, T, B> Iterator for Nodes<'a, T, B> {
1328    type Item = &'a IndexedNode<T, B>;
1329
1330    #[inline(always)]
1331    fn next(&mut self) -> Option<&'a IndexedNode<T, B>> {
1332        match &mut self.0 {
1333            None => None,
1334            Some(it) => it.next(),
1335        }
1336    }
1337}
1338
1339impl<T: Eq + Hash, B: Eq + Hash> TryFromJsonObject<T, B> for Node<T, B> {
1340    fn try_from_json_object_in(vocabulary: &mut impl VocabularyMut<Iri = T, BlankId = B>, mut object: jstrict::Object) -> Result<Self, InvalidExpandedJson> {
1341        let id = match object.remove_unique("@id").map_err(InvalidExpandedJson::duplicate_key)? {
1342            Some(entry) => Some(Id::try_from_json_in(vocabulary, entry.value)?),
1343            None => None,
1344        };
1345
1346        let types = match object.remove_unique("@type").map_err(InvalidExpandedJson::duplicate_key)? {
1347            Some(entry) => Some(Vec::try_from_json_in(vocabulary, entry.value)?),
1348            None => None,
1349        };
1350
1351        let graph = match object.remove_unique("@graph").map_err(InvalidExpandedJson::duplicate_key)? {
1352            Some(entry) => Some(Vec::try_from_json_in(vocabulary, entry.value)?),
1353            None => None,
1354        };
1355
1356        let included = match object.remove_unique("@included").map_err(InvalidExpandedJson::duplicate_key)? {
1357            Some(entry) => Some(Vec::try_from_json_in(vocabulary, entry.value)?),
1358            None => None,
1359        };
1360
1361        let reverse_properties = match object.remove_unique("@reverse").map_err(InvalidExpandedJson::duplicate_key)? {
1362            Some(entry) => Some(ReverseProperties::try_from_json_in(vocabulary, entry.value)?),
1363            None => None,
1364        };
1365
1366        let properties = Properties::try_from_json_object_in(vocabulary, object)?;
1367
1368        Ok(Self {
1369            id,
1370            types,
1371            graph,
1372            included,
1373            properties,
1374            reverse_properties,
1375        })
1376    }
1377}
1378
1379impl<T, B, N: Vocabulary<Iri = T, BlankId = B>> IntoJsonWithContext<N> for Node<T, B> {
1380    fn into_json_with(self, vocabulary: &N) -> jstrict::Value {
1381        let mut obj = jstrict::Object::new();
1382
1383        if let Some(id) = self.id {
1384            obj.insert("@id".into(), id.into_with(vocabulary).into_json());
1385        }
1386
1387        if let Some(types) = self.types
1388            && !types.is_empty()
1389        {
1390            let value = types.into_with(vocabulary).into_json();
1391
1392            obj.insert("@type".into(), value);
1393        }
1394
1395        if let Some(graph) = self.graph {
1396            obj.insert("@graph".into(), graph.into_with(vocabulary).into_json());
1397        }
1398
1399        if let Some(included) = self.included {
1400            obj.insert("@included".into(), included.into_with(vocabulary).into_json());
1401        }
1402
1403        if let Some(reverse_properties) = self.reverse_properties {
1404            obj.insert("@reverse".into(), reverse_properties.into_with(vocabulary).into_json());
1405        }
1406
1407        for (prop, objects) in self.properties {
1408            obj.insert(prop.with(vocabulary).to_string().into(), objects.into_json_with(vocabulary));
1409        }
1410
1411        obj.into()
1412    }
1413}