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