Skip to main content

jsonld_syntax/context/term_definition/
mod.rs

1use crate::{CompactIri, CompactIriBuf, Container, ContainerKind, Direction, Keyword, LenientLangTag, LenientLangTagBuf, Nullable, container, context};
2use iri_rs::{Iri, IriBuf};
3use rdfx::{BlankId, BlankIdBuf};
4
5mod id;
6mod index;
7mod nest;
8mod type_;
9
10pub use id::*;
11pub use index::*;
12pub use nest::*;
13pub use type_::*;
14
15/// Definition bound to a term by a context.
16#[derive(PartialEq, Eq, Clone, Debug)]
17#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
18#[cfg_attr(feature = "serde", serde(untagged))]
19pub enum TermDefinition {
20    /// A string mapping the term directly to an IRI, a compact IRI or a blank
21    /// node identifier.
22    Simple(Simple),
23    /// An object, which can set more about the term than the IRI it maps to.
24    Expanded(Box<Expanded>),
25}
26
27impl TermDefinition {
28    /// Checks whether this definition is in expanded form.
29    #[must_use]
30    pub fn is_expanded(&self) -> bool {
31        matches!(self, Self::Expanded(_))
32    }
33
34    /// Checks whether this definition is written as a JSON object, which is the
35    /// case exactly when it is in expanded form.
36    #[must_use]
37    pub fn is_object(&self) -> bool {
38        self.is_expanded()
39    }
40
41    /// Returns a borrowed view of this definition in expanded form.
42    ///
43    /// A simple definition is presented as an expanded one whose only entry is
44    /// the `@id` it maps to.
45    #[must_use]
46    pub fn as_expanded(&self) -> ExpandedRef<'_> {
47        match self {
48            Self::Simple(term) => ExpandedRef {
49                id: Some(Nullable::Some(term.as_str().into())),
50                ..Default::default()
51            },
52            Self::Expanded(e) => e.as_expanded_ref(),
53        }
54    }
55}
56
57#[derive(PartialEq, Eq, Clone, Debug)]
58#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(transparent))]
59/// Simple term definition: the string a term maps to.
60///
61/// Kept unvalidated: the string may be an IRI, a compact IRI, a blank node
62/// identifier or another term, and which one it is can only be told once the
63/// context is processed.
64pub struct Simple(pub(crate) String);
65
66impl Simple {
67    /// Parses this definition as an IRI, returning `None` if it is not one.
68    #[must_use]
69    pub fn as_iri(&self) -> Option<Iri<&str>> {
70        Iri::parse(self.0.as_str()).ok()
71    }
72
73    /// Parses this definition as a compact IRI, returning `None` if it is not
74    /// one.
75    #[must_use]
76    pub fn as_compact_iri(&self) -> Option<&CompactIri> {
77        CompactIri::new(&self.0).ok()
78    }
79
80    /// Parses this definition as a blank node identifier, returning `None` if
81    /// it is not one.
82    #[must_use]
83    pub fn as_blank_id(&self) -> Option<&BlankId> {
84        BlankId::new(&self.0).ok()
85    }
86
87    /// Returns this value as a string slice.
88    #[must_use]
89    pub fn as_str(&self) -> &str {
90        &self.0
91    }
92
93    /// Unwraps the underlying string.
94    #[must_use]
95    pub fn into_string(self) -> String {
96        self.0
97    }
98}
99
100impl From<IriBuf> for Simple {
101    fn from(value: IriBuf) -> Self {
102        Self(value.into_inner())
103    }
104}
105
106impl From<CompactIriBuf> for Simple {
107    fn from(value: CompactIriBuf) -> Self {
108        Self(value.into_string())
109    }
110}
111
112impl From<BlankIdBuf> for Simple {
113    fn from(value: BlankIdBuf) -> Self {
114        Self(value.to_string())
115    }
116}
117
118/// Expanded term definition.
119#[derive(PartialEq, Eq, Clone, Default, Debug)]
120#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
121pub struct Expanded {
122    #[cfg_attr(
123        feature = "serde",
124        serde(rename = "@id", default, deserialize_with = "Nullable::optional", skip_serializing_if = "Option::is_none")
125    )]
126    /// The `@id` entry, giving the IRI the term expands to.
127    pub id: Option<Nullable<Id>>,
128
129    #[cfg_attr(
130        feature = "serde",
131        serde(rename = "@type", default, deserialize_with = "Nullable::optional", skip_serializing_if = "Option::is_none")
132    )]
133    /// The `@type` entry, giving the type of the values of the term.
134    pub type_: Option<Nullable<Type>>,
135
136    #[cfg_attr(feature = "serde", serde(rename = "@context", default, skip_serializing_if = "Option::is_none"))]
137    /// The `@context` entry, holding a context scoped to the term.
138    pub context: Option<Box<context::Context>>,
139
140    #[cfg_attr(feature = "serde", serde(rename = "@reverse", default, skip_serializing_if = "Option::is_none"))]
141    /// The `@reverse` entry, mapping the term to a reverse property.
142    pub reverse: Option<context::definition::Key>,
143
144    #[cfg_attr(feature = "serde", serde(rename = "@index", default, skip_serializing_if = "Option::is_none"))]
145    /// The `@index` entry, naming the property that carries the index of the
146    /// values in an index map.
147    pub index: Option<Index>,
148
149    #[cfg_attr(
150        feature = "serde",
151        serde(rename = "@language", default, deserialize_with = "Nullable::optional", skip_serializing_if = "Option::is_none")
152    )]
153    /// The `@language` entry, tagging string values with a language.
154    pub language: Option<Nullable<LenientLangTagBuf>>,
155
156    #[cfg_attr(
157        feature = "serde",
158        serde(rename = "@direction", default, deserialize_with = "Nullable::optional", skip_serializing_if = "Option::is_none")
159    )]
160    /// The `@direction` entry, setting the base direction of string values.
161    pub direction: Option<Nullable<Direction>>,
162
163    #[cfg_attr(
164        feature = "serde",
165        serde(rename = "@container", default, deserialize_with = "Nullable::optional", skip_serializing_if = "Option::is_none")
166    )]
167    /// The `@container` entry, declaring the container the values of the term
168    /// are held in.
169    pub container: Option<Nullable<Container>>,
170
171    #[cfg_attr(feature = "serde", serde(rename = "@nest", default, skip_serializing_if = "Option::is_none"))]
172    /// The `@nest` entry, naming the term under which this property is nested.
173    pub nest: Option<Nest>,
174
175    #[cfg_attr(feature = "serde", serde(rename = "@prefix", default, skip_serializing_if = "Option::is_none"))]
176    /// The `@prefix` entry, allowing the term to be used as the prefix of a
177    /// compact IRI.
178    pub prefix: Option<bool>,
179
180    #[cfg_attr(feature = "serde", serde(rename = "@propagate", default, skip_serializing_if = "Option::is_none"))]
181    /// The `@propagate` entry, controlling whether the context survives into node objects.
182    pub propagate: Option<bool>,
183
184    #[cfg_attr(feature = "serde", serde(rename = "@protected", default, skip_serializing_if = "Option::is_none"))]
185    /// The `@protected` entry, forbidding redefinition of the term.
186    pub protected: Option<bool>,
187}
188
189impl Expanded {
190    /// Creates an expanded term definition with no entry set.
191    #[must_use]
192    pub fn new() -> Self {
193        Self::default()
194    }
195
196    /// Checks whether this definition is equivalent to `null`, which unsets the
197    /// term: no entry is set, except possibly an `@id` explicitly set to `null`.
198    #[must_use]
199    pub fn is_null(&self) -> bool {
200        matches!(&self.id, None | Some(Nullable::Null))
201            && self.type_.is_none()
202            && self.context.is_none()
203            && self.reverse.is_none()
204            && self.index.is_none()
205            && self.language.is_none()
206            && self.direction.is_none()
207            && self.container.is_none()
208            && self.nest.is_none()
209            && self.prefix.is_none()
210            && self.propagate.is_none()
211            && self.protected.is_none()
212    }
213
214    /// Checks whether this definition can be written in simple form: `@id` is
215    /// set to a non-null value and no other entry is set.
216    #[must_use]
217    pub fn is_simple_definition(&self) -> bool {
218        matches!(&self.id, Some(Nullable::Some(_)))
219            && self.type_.is_none()
220            && self.context.is_none()
221            && self.reverse.is_none()
222            && self.index.is_none()
223            && self.language.is_none()
224            && self.direction.is_none()
225            && self.container.is_none()
226            && self.nest.is_none()
227            && self.prefix.is_none()
228            && self.propagate.is_none()
229            && self.protected.is_none()
230    }
231
232    /// Reduces this definition to the shortest equivalent form: `null` when it
233    /// unsets the term, a simple string definition when it carries nothing but
234    /// an `@id`, and the expanded form otherwise.
235    #[must_use]
236    pub fn simplify(self) -> Nullable<TermDefinition> {
237        if self.is_null() {
238            return Nullable::Null;
239        }
240        match self {
241            Self {
242                id: Some(Nullable::Some(id)),
243                type_: None,
244                context: None,
245                reverse: None,
246                index: None,
247                language: None,
248                direction: None,
249                container: None,
250                nest: None,
251                prefix: None,
252                propagate: None,
253                protected: None,
254            } => Nullable::Some(TermDefinition::Simple(Simple(id.into_string()))),
255            other => Nullable::Some(TermDefinition::Expanded(Box::new(other))),
256        }
257    }
258
259    /// Returns an iterator over the entries this definition sets, in the order
260    /// they are declared on this struct.
261    pub fn iter(&self) -> Entries<'_> {
262        Entries {
263            id: self.id.as_ref().map(Nullable::as_ref),
264            type_: self.type_.as_ref().map(Nullable::as_ref),
265            context: self.context.as_deref(),
266            reverse: self.reverse.as_ref(),
267            index: self.index.as_ref(),
268            language: self.language.as_ref().map(Nullable::as_ref),
269            direction: self.direction,
270            container: self.container.as_ref().map(Nullable::as_ref),
271            nest: self.nest.as_ref(),
272            prefix: self.prefix,
273            propagate: self.propagate,
274            protected: self.protected,
275        }
276    }
277
278    /// Returns a borrowed view of this definition.
279    pub fn as_expanded_ref(&self) -> ExpandedRef<'_> {
280        ExpandedRef {
281            id: self.id.as_ref().map(|i| i.as_ref().map(|id| id.as_id_ref())),
282            type_: self.type_.as_ref().map(Nullable::as_ref),
283            context: self.context.as_deref(),
284            reverse: self.reverse.as_ref(),
285            index: self.index.as_ref(),
286            language: self.language.as_ref().map(|n| n.as_ref().map(LenientLangTagBuf::as_lenient_lang_tag_ref)),
287            direction: self.direction,
288            container: self.container.as_ref().map(Nullable::as_ref),
289            nest: self.nest.as_ref(),
290            prefix: self.prefix,
291            propagate: self.propagate,
292            protected: self.protected,
293        }
294    }
295}
296
297/// Borrowed view of a term definition in expanded form.
298///
299/// Also used to present a simple definition, or `null`, in expanded form; see
300/// [`TermDefinition::as_expanded`].
301#[derive(Debug, Default)]
302pub struct ExpandedRef<'a> {
303    /// The `@id` entry, giving the IRI the term expands to.
304    pub id: Option<Nullable<IdRef<'a>>>,
305    /// The `@type` entry, giving the type of the values of the term.
306    pub type_: Option<Nullable<&'a Type>>,
307    /// The `@context` entry, holding a context scoped to the term.
308    pub context: Option<&'a context::Context>,
309    /// The `@reverse` entry, mapping the term to a reverse property.
310    pub reverse: Option<&'a context::definition::Key>,
311    /// The `@index` entry, naming the property that carries the index of the
312    /// values in an index map.
313    pub index: Option<&'a Index>,
314    /// The `@language` entry, tagging string values with a language.
315    pub language: Option<Nullable<&'a LenientLangTag>>,
316    /// The `@direction` entry, setting the base direction of string values.
317    pub direction: Option<Nullable<Direction>>,
318    /// The `@container` entry, declaring the container the values of the term
319    /// are held in.
320    pub container: Option<Nullable<&'a Container>>,
321    /// The `@nest` entry, naming the term under which this property is nested.
322    pub nest: Option<&'a Nest>,
323    /// The `@prefix` entry, allowing the term to be used as the prefix of a
324    /// compact IRI.
325    pub prefix: Option<bool>,
326    /// The `@propagate` entry, controlling whether the context survives into
327    /// node objects.
328    pub propagate: Option<bool>,
329    /// The `@protected` entry, forbidding redefinition of the term.
330    pub protected: Option<bool>,
331}
332
333impl<'a> From<Nullable<&'a TermDefinition>> for ExpandedRef<'a> {
334    fn from(value: Nullable<&'a TermDefinition>) -> Self {
335        match value {
336            Nullable::Some(d) => d.as_expanded(),
337            Nullable::Null => Self {
338                id: Some(Nullable::Null),
339                ..Default::default()
340            },
341        }
342    }
343}
344
345/// Iterator over the entries of an expanded term definition.
346pub struct Entries<'a> {
347    id: Option<Nullable<&'a Id>>,
348    type_: Option<Nullable<&'a Type>>,
349    context: Option<&'a context::Context>,
350    reverse: Option<&'a context::definition::Key>,
351    index: Option<&'a Index>,
352    language: Option<Nullable<&'a LenientLangTagBuf>>,
353    direction: Option<Nullable<Direction>>,
354    container: Option<Nullable<&'a Container>>,
355    nest: Option<&'a Nest>,
356    prefix: Option<bool>,
357    propagate: Option<bool>,
358    protected: Option<bool>,
359}
360
361/// Entry of an expanded term definition, key and value together.
362pub enum EntryRef<'a> {
363    /// The `@id` entry, giving the IRI the term expands to.
364    Id(Nullable<&'a Id>),
365    /// The `@type` entry, giving the type of the values of the term.
366    Type(Nullable<&'a Type>),
367    /// The `@context` entry, holding a context scoped to the term.
368    Context(&'a context::Context),
369    /// The `@reverse` entry, mapping the term to a reverse property.
370    Reverse(&'a context::definition::Key),
371    /// The `@index` entry, naming the property that carries the index of the
372    /// values in an index map.
373    Index(&'a Index),
374    /// The `@language` entry, tagging string values with a language.
375    Language(Nullable<&'a LenientLangTagBuf>),
376    /// The `@direction` entry, setting the base direction of string values.
377    Direction(Nullable<Direction>),
378    /// The `@container` entry, declaring the container the values of the term
379    /// are held in.
380    Container(Nullable<&'a Container>),
381    /// The `@nest` entry, naming the term under which this property is nested.
382    Nest(&'a Nest),
383    /// The `@prefix` entry, allowing the term to be used as the prefix of a
384    /// compact IRI.
385    Prefix(bool),
386    /// The `@propagate` entry, controlling whether the context survives into node objects.
387    Propagate(bool),
388    /// The `@protected` entry, forbidding redefinition of the term.
389    Protected(bool),
390}
391
392impl<'a> EntryRef<'a> {
393    /// Returns the key of this entry, taking `self` by value.
394    #[must_use]
395    pub fn into_key(self) -> EntryKey {
396        match self {
397            Self::Id(_) => EntryKey::Id,
398            Self::Type(_) => EntryKey::Type,
399            Self::Context(_) => EntryKey::Context,
400            Self::Reverse(_) => EntryKey::Reverse,
401            Self::Index(_) => EntryKey::Index,
402            Self::Language(_) => EntryKey::Language,
403            Self::Direction(_) => EntryKey::Direction,
404            Self::Container(_) => EntryKey::Container,
405            Self::Nest(_) => EntryKey::Nest,
406            Self::Prefix(_) => EntryKey::Prefix,
407            Self::Propagate(_) => EntryKey::Propagate,
408            Self::Protected(_) => EntryKey::Protected,
409        }
410    }
411
412    /// Returns the key of this entry.
413    #[must_use]
414    pub fn key(&self) -> EntryKey {
415        match self {
416            Self::Id(_) => EntryKey::Id,
417            Self::Type(_) => EntryKey::Type,
418            Self::Context(_) => EntryKey::Context,
419            Self::Reverse(_) => EntryKey::Reverse,
420            Self::Index(_) => EntryKey::Index,
421            Self::Language(_) => EntryKey::Language,
422            Self::Direction(_) => EntryKey::Direction,
423            Self::Container(_) => EntryKey::Container,
424            Self::Nest(_) => EntryKey::Nest,
425            Self::Prefix(_) => EntryKey::Prefix,
426            Self::Propagate(_) => EntryKey::Propagate,
427            Self::Protected(_) => EntryKey::Protected,
428        }
429    }
430
431    /// Returns the value of this entry, taking `self` by value.
432    #[must_use]
433    pub fn into_value(self) -> EntryValueRef<'a> {
434        self.value()
435    }
436
437    /// Returns the value of this entry.
438    #[must_use]
439    pub fn value(&self) -> EntryValueRef<'a> {
440        match self {
441            Self::Id(e) => EntryValueRef::Id(*e),
442            Self::Type(e) => EntryValueRef::Type(*e),
443            Self::Context(e) => EntryValueRef::Context(e),
444            Self::Reverse(e) => EntryValueRef::Reverse(e),
445            Self::Index(e) => EntryValueRef::Index(e),
446            Self::Language(e) => EntryValueRef::Language(*e),
447            Self::Direction(e) => EntryValueRef::Direction(*e),
448            Self::Container(e) => EntryValueRef::Container(*e),
449            Self::Nest(e) => EntryValueRef::Nest(e),
450            Self::Prefix(e) => EntryValueRef::Prefix(*e),
451            Self::Propagate(e) => EntryValueRef::Propagate(*e),
452            Self::Protected(e) => EntryValueRef::Protected(*e),
453        }
454    }
455
456    /// Returns the key and value of this entry, taking `self` by value.
457    #[must_use]
458    pub fn into_key_value(self) -> (EntryKey, EntryValueRef<'a>) {
459        self.key_value()
460    }
461
462    /// Returns the key and value of this entry.
463    #[must_use]
464    pub fn key_value(&self) -> (EntryKey, EntryValueRef<'a>) {
465        match self {
466            Self::Id(e) => (EntryKey::Id, EntryValueRef::Id(*e)),
467            Self::Type(e) => (EntryKey::Type, EntryValueRef::Type(*e)),
468            Self::Context(e) => (EntryKey::Context, EntryValueRef::Context(e)),
469            Self::Reverse(e) => (EntryKey::Reverse, EntryValueRef::Reverse(e)),
470            Self::Index(e) => (EntryKey::Index, EntryValueRef::Index(e)),
471            Self::Language(e) => (EntryKey::Language, EntryValueRef::Language(*e)),
472            Self::Direction(e) => (EntryKey::Direction, EntryValueRef::Direction(*e)),
473            Self::Container(e) => (EntryKey::Container, EntryValueRef::Container(*e)),
474            Self::Nest(e) => (EntryKey::Nest, EntryValueRef::Nest(e)),
475            Self::Prefix(e) => (EntryKey::Prefix, EntryValueRef::Prefix(*e)),
476            Self::Propagate(e) => (EntryKey::Propagate, EntryValueRef::Propagate(*e)),
477            Self::Protected(e) => (EntryKey::Protected, EntryValueRef::Protected(*e)),
478        }
479    }
480}
481
482/// Key of an expanded term definition entry.
483pub enum EntryKey {
484    /// The `@id` entry, giving the IRI the term expands to.
485    Id,
486    /// The `@type` entry, giving the type of the values of the term.
487    Type,
488    /// The `@context` entry, holding a context scoped to the term.
489    Context,
490    /// The `@reverse` entry, mapping the term to a reverse property.
491    Reverse,
492    /// The `@index` entry, naming the property that carries the index of the
493    /// values in an index map.
494    Index,
495    /// The `@language` entry, tagging string values with a language.
496    Language,
497    /// The `@direction` entry, setting the base direction of string values.
498    Direction,
499    /// The `@container` entry, declaring the container the values of the term
500    /// are held in.
501    Container,
502    /// The `@nest` entry, naming the term under which this property is nested.
503    Nest,
504    /// The `@prefix` entry, allowing the term to be used as the prefix of a
505    /// compact IRI.
506    Prefix,
507    /// The `@propagate` entry, controlling whether the context survives into node objects.
508    Propagate,
509    /// The `@protected` entry, forbidding redefinition of the term.
510    Protected,
511}
512
513impl EntryKey {
514    /// Returns the keyword naming this entry.
515    #[must_use]
516    pub fn keyword(&self) -> Keyword {
517        match self {
518            Self::Id => Keyword::Id,
519            Self::Type => Keyword::Type,
520            Self::Context => Keyword::Context,
521            Self::Reverse => Keyword::Reverse,
522            Self::Index => Keyword::Index,
523            Self::Language => Keyword::Language,
524            Self::Direction => Keyword::Direction,
525            Self::Container => Keyword::Container,
526            Self::Nest => Keyword::Nest,
527            Self::Prefix => Keyword::Prefix,
528            Self::Propagate => Keyword::Propagate,
529            Self::Protected => Keyword::Protected,
530        }
531    }
532
533    /// Returns the keyword naming this entry as a string, such as `"@id"`.
534    #[must_use]
535    pub fn as_str(&self) -> &'static str {
536        self.keyword().into_str()
537    }
538}
539
540/// Value of an expanded term definition entry.
541pub enum EntryValueRef<'a> {
542    /// The `@id` entry, giving the IRI the term expands to.
543    Id(Nullable<&'a Id>),
544    /// The `@type` entry, giving the type of the values of the term.
545    Type(Nullable<&'a Type>),
546    /// The `@context` entry, holding a context scoped to the term.
547    Context(&'a context::Context),
548    /// The `@reverse` entry, mapping the term to a reverse property.
549    Reverse(&'a context::definition::Key),
550    /// The `@index` entry, naming the property that carries the index of the
551    /// values in an index map.
552    Index(&'a Index),
553    /// The `@language` entry, tagging string values with a language.
554    Language(Nullable<&'a LenientLangTagBuf>),
555    /// The `@direction` entry, setting the base direction of string values.
556    Direction(Nullable<Direction>),
557    /// The `@container` entry, declaring the container the values of the term
558    /// are held in.
559    Container(Nullable<&'a Container>),
560    /// The `@nest` entry, naming the term under which this property is nested.
561    Nest(&'a Nest),
562    /// The `@prefix` entry, allowing the term to be used as the prefix of a
563    /// compact IRI.
564    Prefix(bool),
565    /// The `@propagate` entry, controlling whether the context survives into node objects.
566    Propagate(bool),
567    /// The `@protected` entry, forbidding redefinition of the term.
568    Protected(bool),
569}
570
571impl EntryValueRef<'_> {
572    /// Checks whether this value is a JSON object, which only the scoped
573    /// `@context` can be.
574    #[must_use]
575    pub fn is_object(&self) -> bool {
576        match self {
577            Self::Context(c) => c.is_object(),
578            _ => false,
579        }
580    }
581
582    /// Checks whether this value is a JSON array, which only a multi-valued
583    /// `@container` can be.
584    #[must_use]
585    pub fn is_array(&self) -> bool {
586        match self {
587            Self::Container(Nullable::Some(c)) => c.is_array(),
588            _ => false,
589        }
590    }
591}
592
593impl<'a> Iterator for Entries<'a> {
594    type Item = EntryRef<'a>;
595
596    fn size_hint(&self) -> (usize, Option<usize>) {
597        let mut len = 0;
598
599        if self.id.is_some() {
600            len += 1;
601        }
602
603        if self.type_.is_some() {
604            len += 1;
605        }
606
607        if self.context.is_some() {
608            len += 1;
609        }
610
611        if self.reverse.is_some() {
612            len += 1;
613        }
614
615        if self.index.is_some() {
616            len += 1;
617        }
618
619        if self.language.is_some() {
620            len += 1;
621        }
622
623        if self.direction.is_some() {
624            len += 1;
625        }
626
627        if self.container.is_some() {
628            len += 1;
629        }
630
631        if self.nest.is_some() {
632            len += 1;
633        }
634
635        if self.prefix.is_some() {
636            len += 1;
637        }
638
639        if self.propagate.is_some() {
640            len += 1;
641        }
642
643        if self.protected.is_some() {
644            len += 1;
645        }
646
647        (len, Some(len))
648    }
649
650    fn next(&mut self) -> Option<Self::Item> {
651        match self.id.take() {
652            Some(value) => Some(EntryRef::Id(value)),
653            None => match self.type_.take() {
654                Some(value) => Some(EntryRef::Type(value)),
655                None => match self.context.take() {
656                    Some(value) => Some(EntryRef::Context(value)),
657                    None => match self.reverse.take() {
658                        Some(value) => Some(EntryRef::Reverse(value)),
659                        None => match self.index.take() {
660                            Some(value) => Some(EntryRef::Index(value)),
661                            None => match self.language.take() {
662                                Some(value) => Some(EntryRef::Language(value)),
663                                None => match self.direction.take() {
664                                    Some(value) => Some(EntryRef::Direction(value)),
665                                    None => match self.container.take() {
666                                        Some(value) => Some(EntryRef::Container(value)),
667                                        None => match self.nest.take() {
668                                            Some(value) => Some(EntryRef::Nest(value)),
669                                            None => match self.prefix.take() {
670                                                Some(value) => Some(EntryRef::Prefix(value)),
671                                                None => match self.propagate.take() {
672                                                    Some(value) => Some(EntryRef::Propagate(value)),
673                                                    None => self.protected.take().map(EntryRef::Protected),
674                                                },
675                                            },
676                                        },
677                                    },
678                                },
679                            },
680                        },
681                    },
682                },
683            },
684        }
685    }
686}
687
688impl ExactSizeIterator for Entries<'_> {}
689
690/// Fragment of a term definition.
691pub enum FragmentRef<'a> {
692    /// An entry of the definition, key and value together.
693    Entry(EntryRef<'a>),
694
695    /// The key of an entry of the definition.
696    Key(EntryKey),
697
698    /// The value of an entry of the definition.
699    Value(EntryValueRef<'a>),
700
701    /// One item of an array-valued `@container` entry.
702    ContainerFragment(&'a ContainerKind),
703}
704
705impl<'a> FragmentRef<'a> {
706    /// Checks whether this fragment is an entry key.
707    #[must_use]
708    pub fn is_key(&self) -> bool {
709        matches!(self, Self::Key(_))
710    }
711
712    /// Checks whether this fragment is an entry, key and value together.
713    #[must_use]
714    pub fn is_entry(&self) -> bool {
715        matches!(self, Self::Entry(_))
716    }
717
718    /// Checks whether this fragment is a JSON array.
719    #[must_use]
720    pub fn is_array(&self) -> bool {
721        match self {
722            Self::Value(v) => v.is_array(),
723            _ => false,
724        }
725    }
726
727    /// Checks whether this fragment is a JSON object.
728    #[must_use]
729    pub fn is_object(&self) -> bool {
730        match self {
731            Self::Value(v) => v.is_object(),
732            _ => false,
733        }
734    }
735
736    /// Returns an iterator over the fragments directly contained in this one.
737    #[must_use]
738    pub fn sub_fragments(&self) -> SubFragments<'a> {
739        match self {
740            Self::Value(EntryValueRef::Container(Nullable::Some(c))) => SubFragments::Container(c.sub_fragments()),
741            _ => SubFragments::None,
742        }
743    }
744}
745
746/// Iterator over the fragments held by a term definition entry.
747pub enum SubFragments<'a> {
748    /// Nothing to iterate over.
749    None,
750    /// The items of an array-valued `@container` entry.
751    Container(container::SubValues<'a>),
752}
753
754impl<'a> Iterator for SubFragments<'a> {
755    type Item = FragmentRef<'a>;
756
757    fn next(&mut self) -> Option<Self::Item> {
758        match self {
759            Self::None => None,
760            Self::Container(c) => c.next().map(FragmentRef::ContainerFragment),
761        }
762    }
763}