Skip to main content

jsonld_syntax/
container.rs

1use crate::Keyword;
2
3#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
4#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
5/// A single `@container` value.
6pub enum ContainerKind {
7    #[cfg_attr(feature = "serde", serde(rename = "@graph"))]
8    /// `@graph`: the values of the term are graph objects.
9    Graph,
10
11    #[cfg_attr(feature = "serde", serde(rename = "@id"))]
12    /// `@id`: the values of the term form an id map, keyed by node identifier.
13    Id,
14
15    #[cfg_attr(feature = "serde", serde(rename = "@index"))]
16    /// `@index`: the values of the term form an index map, keyed by an
17    /// arbitrary index string.
18    Index,
19
20    #[cfg_attr(feature = "serde", serde(rename = "@language"))]
21    /// `@language`: the values of the term form a language map, keyed by
22    /// language tag.
23    Language,
24
25    #[cfg_attr(feature = "serde", serde(rename = "@list"))]
26    /// `@list`: the values of the term are an ordered list.
27    List,
28
29    #[cfg_attr(feature = "serde", serde(rename = "@set"))]
30    /// `@set`: the values of the term are always represented as an array.
31    Set,
32
33    #[cfg_attr(feature = "serde", serde(rename = "@type"))]
34    /// `@type`: the values of the term form a type map, keyed by node type.
35    Type,
36}
37
38impl ContainerKind {
39    /// Returns the keyword naming this container, taking `self` by value.
40    #[must_use]
41    pub fn into_keyword(self) -> Keyword {
42        self.into()
43    }
44
45    /// Returns the keyword naming this container.
46    #[must_use]
47    pub fn keyword(&self) -> Keyword {
48        self.into_keyword()
49    }
50
51    /// Returns the keyword naming this container as a string, such as
52    /// `"@set"`.
53    #[must_use]
54    pub fn as_str(&self) -> &'static str {
55        self.into_keyword().into_str()
56    }
57}
58
59impl<'a> TryFrom<&'a str> for ContainerKind {
60    type Error = &'a str;
61
62    fn try_from(str: &'a str) -> Result<ContainerKind, &'a str> {
63        use ContainerKind::{Graph, Id, Index, Language, List, Set, Type};
64        match str {
65            "@graph" => Ok(Graph),
66            "@id" => Ok(Id),
67            "@index" => Ok(Index),
68            "@language" => Ok(Language),
69            "@list" => Ok(List),
70            "@set" => Ok(Set),
71            "@type" => Ok(Type),
72            _ => Err(str),
73        }
74    }
75}
76
77impl TryFrom<Keyword> for ContainerKind {
78    type Error = Keyword;
79
80    fn try_from(k: Keyword) -> Result<ContainerKind, Keyword> {
81        use ContainerKind::{Graph, Id, Index, Language, List, Set, Type};
82        match k {
83            Keyword::Graph => Ok(Graph),
84            Keyword::Id => Ok(Id),
85            Keyword::Index => Ok(Index),
86            Keyword::Language => Ok(Language),
87            Keyword::List => Ok(List),
88            Keyword::Set => Ok(Set),
89            Keyword::Type => Ok(Type),
90            k => Err(k),
91        }
92    }
93}
94
95impl From<ContainerKind> for Keyword {
96    fn from(c: ContainerKind) -> Keyword {
97        use ContainerKind::{Graph, Id, Index, Language, List, Set, Type};
98        match c {
99            Graph => Keyword::Graph,
100            Id => Keyword::Id,
101            Index => Keyword::Index,
102            Language => Keyword::Language,
103            List => Keyword::List,
104            Set => Keyword::Set,
105            Type => Keyword::Type,
106        }
107    }
108}
109
110impl From<ContainerKind> for Container {
111    fn from(c: ContainerKind) -> Self {
112        Container::One(c)
113    }
114}
115
116#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
117#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(untagged))]
118/// The `@container` entry: one value, or an array of them.
119pub enum Container {
120    /// A single container, written as a string.
121    One(ContainerKind),
122    /// Several containers, written as an array of strings.
123    Many(Vec<ContainerKind>),
124}
125
126impl Container {
127    /// Checks whether this entry is written as a JSON array.
128    #[must_use]
129    pub fn is_array(&self) -> bool {
130        matches!(self, Self::Many(_))
131    }
132
133    /// Returns an iterator over the array items of this entry.
134    ///
135    /// The iterator is empty for a single container, which is written as a
136    /// string and therefore has no items of its own.
137    #[must_use]
138    pub fn sub_fragments(&self) -> SubValues<'_> {
139        match self {
140            Self::One(_) => SubValues::None,
141            Self::Many(m) => SubValues::Many(m.iter()),
142        }
143    }
144}
145
146/// Iterator over the array items of a `@container` entry.
147pub enum SubValues<'a> {
148    /// Nothing to iterate over: the entry held a single container.
149    None,
150    /// The items of an array-valued entry.
151    Many(std::slice::Iter<'a, ContainerKind>),
152}
153
154impl<'a> Iterator for SubValues<'a> {
155    type Item = &'a ContainerKind;
156
157    fn size_hint(&self) -> (usize, Option<usize>) {
158        match self {
159            Self::None => (0, Some(0)),
160            Self::Many(m) => m.size_hint(),
161        }
162    }
163
164    fn next(&mut self) -> Option<Self::Item> {
165        match self {
166            Self::None => None,
167            Self::Many(m) => m.next(),
168        }
169    }
170}
171
172impl ExactSizeIterator for SubValues<'_> {}
173
174impl DoubleEndedIterator for SubValues<'_> {
175    fn next_back(&mut self) -> Option<Self::Item> {
176        match self {
177            Self::None => None,
178            Self::Many(m) => m.next_back(),
179        }
180    }
181}