Skip to main content

oxirs_core/jsonld/
profile.rs

1use std::ops::{BitOr, BitOrAssign};
2
3/// JSON-Ld profile.
4///
5/// This enumeration is non exhaustive. New profiles might be added in the future.
6///
7/// See [JSON-LD specification](https://www.w3.org/TR/json-ld11/#iana-considerations) for a list of profiles.
8#[derive(Eq, PartialEq, Debug, Clone, Copy, Hash)]
9#[non_exhaustive]
10pub enum JsonLdProfile {
11    /// [expanded JSON-LD document form](https://www.w3.org/TR/json-ld11/#dfn-expanded-document-form)
12    Expanded,
13    /// [compacted JSON-LD document form](https://www.w3.org/TR/json-ld11/#dfn-compacted-document-form)
14    Compacted,
15    /// [JSON-LD context document](https://www.w3.org/TR/json-ld11/#dfn-context-document)
16    Context,
17    /// [flattened JSON-LD document form](https://www.w3.org/TR/json-ld11/#dfn-flattened-document-form)
18    Flattened,
19    /// [JSON-LD frame document](https://www.w3.org/TR/json-ld11-framing/#dfn-frame)
20    Frame,
21    /// [framed JSON-LD document form](https://www.w3.org/TR/json-ld11/#dfn-framed-document-form)
22    Framed,
23    /// [streaming JSON-LD document form](https://www.w3.org/TR/json-ld11-streaming/#dfn-streaming-document)
24    Streaming,
25}
26
27impl JsonLdProfile {
28    /// The profile canonical IRI.
29    ///
30    /// ```
31    /// use oxjsonld::JsonLdProfile;
32    ///
33    /// assert_eq!(
34    ///     JsonLdProfile::Expanded.iri(),
35    ///     "http://www.w3.org/ns/json-ld#expanded"
36    /// )
37    /// ```
38    #[inline]
39    pub const fn iri(self) -> &'static str {
40        match self {
41            Self::Expanded => "http://www.w3.org/ns/json-ld#expanded",
42            Self::Compacted => "http://www.w3.org/ns/json-ld#compacted",
43            Self::Context => "http://www.w3.org/ns/json-ld#context",
44            Self::Flattened => "http://www.w3.org/ns/json-ld#flattened",
45            Self::Frame => "http://www.w3.org/ns/json-ld#frame",
46            Self::Framed => "http://www.w3.org/ns/json-ld#framed",
47            Self::Streaming => "http://www.w3.org/ns/json-ld#streaming",
48        }
49    }
50
51    /// Looks for a known profile from an IRI.
52    ///
53    /// Example:
54    /// ```
55    /// use oxjsonld::JsonLdProfile;
56    ///
57    /// assert_eq!(
58    ///     JsonLdProfile::from_iri("http://www.w3.org/ns/json-ld#expanded"),
59    ///     Some(JsonLdProfile::Expanded)
60    /// )
61    /// ```
62    #[inline]
63    pub fn from_iri(iri: &str) -> Option<Self> {
64        match iri {
65            "http://www.w3.org/ns/json-ld#expanded" => Some(Self::Expanded),
66            "http://www.w3.org/ns/json-ld#compacted" => Some(Self::Compacted),
67            "http://www.w3.org/ns/json-ld#context" => Some(Self::Context),
68            "http://www.w3.org/ns/json-ld#flattened" => Some(Self::Flattened),
69            "http://www.w3.org/ns/json-ld#frame" => Some(Self::Frame),
70            "http://www.w3.org/ns/json-ld#framed" => Some(Self::Framed),
71            "http://www.w3.org/ns/json-ld#streaming" => Some(Self::Streaming),
72            _ => None,
73        }
74    }
75
76    #[inline]
77    const fn to_bit(self) -> u64 {
78        match self {
79            JsonLdProfile::Expanded => 1,
80            JsonLdProfile::Compacted => 2,
81            JsonLdProfile::Context => 4,
82            JsonLdProfile::Flattened => 8,
83            JsonLdProfile::Frame => 16,
84            JsonLdProfile::Framed => 32,
85            JsonLdProfile::Streaming => 64,
86        }
87    }
88}
89
90/// Set of JSON-Ld profiles.
91///
92/// ```
93/// use oxjsonld::{JsonLdProfile, JsonLdProfileSet};
94///
95/// let mut profile_set = JsonLdProfileSet::empty();
96/// profile_set |= JsonLdProfile::Expanded;
97/// profile_set |= JsonLdProfile::Streaming;
98/// assert!(profile_set.contains(JsonLdProfile::Streaming));
99/// assert_eq!(
100///     profile_set.into_iter().collect::<Vec<_>>(),
101///     vec![JsonLdProfile::Expanded, JsonLdProfile::Streaming]
102/// );
103/// ```
104#[derive(Eq, PartialEq, Debug, Clone, Copy, Hash, Default)]
105pub struct JsonLdProfileSet {
106    value: u64,
107}
108
109impl JsonLdProfileSet {
110    #[inline]
111    pub const fn empty() -> Self {
112        Self { value: 0 }
113    }
114
115    #[inline]
116    pub const fn from_profile(profile: JsonLdProfile) -> Self {
117        Self {
118            value: profile.to_bit(),
119        }
120    }
121
122    /// Checks if this profile list contains the given profile.
123    #[inline]
124    pub const fn contains(self, profile: JsonLdProfile) -> bool {
125        self.value & profile.to_bit() != 0
126    }
127}
128
129impl From<JsonLdProfile> for JsonLdProfileSet {
130    #[inline]
131    fn from(profile: JsonLdProfile) -> Self {
132        Self {
133            value: profile.to_bit(),
134        }
135    }
136}
137
138impl IntoIterator for JsonLdProfileSet {
139    type Item = JsonLdProfile;
140    type IntoIter = JsonLdProfileBagIter;
141
142    #[inline]
143    fn into_iter(self) -> JsonLdProfileBagIter {
144        JsonLdProfileBagIter {
145            set: self,
146            possible_values: [
147                JsonLdProfile::Expanded,
148                JsonLdProfile::Compacted,
149                JsonLdProfile::Context,
150                JsonLdProfile::Flattened,
151                JsonLdProfile::Frame,
152                JsonLdProfile::Framed,
153                JsonLdProfile::Streaming,
154            ]
155            .into_iter(),
156        }
157    }
158}
159
160/// Iterator output of [`JsonLdProfileSet::into_iter`].
161pub struct JsonLdProfileBagIter {
162    set: JsonLdProfileSet,
163    possible_values: std::array::IntoIter<JsonLdProfile, 7>,
164}
165
166impl Iterator for JsonLdProfileBagIter {
167    type Item = JsonLdProfile;
168
169    #[inline]
170    fn next(&mut self) -> Option<JsonLdProfile> {
171        loop {
172            let possible_value = self.possible_values.next()?;
173            if self.set.contains(possible_value) {
174                return Some(possible_value);
175            }
176        }
177    }
178
179    #[inline]
180    fn size_hint(&self) -> (usize, Option<usize>) {
181        let size = self
182            .set
183            .value
184            .count_ones()
185            .try_into()
186            .expect("count_ones fits in usize");
187        (size, Some(size))
188    }
189}
190
191impl BitOr for JsonLdProfileSet {
192    type Output = Self;
193
194    #[inline]
195    fn bitor(self, rhs: Self) -> Self {
196        Self {
197            value: self.value | rhs.value,
198        }
199    }
200}
201
202impl BitOr<JsonLdProfile> for JsonLdProfileSet {
203    type Output = JsonLdProfileSet;
204
205    #[inline]
206    fn bitor(self, rhs: JsonLdProfile) -> JsonLdProfileSet {
207        self | JsonLdProfileSet::from(rhs)
208    }
209}
210
211impl BitOr<JsonLdProfileSet> for JsonLdProfile {
212    type Output = JsonLdProfileSet;
213
214    #[inline]
215    fn bitor(self, rhs: JsonLdProfileSet) -> JsonLdProfileSet {
216        JsonLdProfileSet::from(self) | rhs
217    }
218}
219
220impl BitOr for JsonLdProfile {
221    type Output = JsonLdProfileSet;
222
223    #[inline]
224    fn bitor(self, rhs: Self) -> JsonLdProfileSet {
225        JsonLdProfileSet::from(self) | JsonLdProfileSet::from(rhs)
226    }
227}
228
229impl BitOrAssign for JsonLdProfileSet {
230    #[inline]
231    fn bitor_assign(&mut self, rhs: Self) {
232        self.value |= rhs.value;
233    }
234}
235
236impl BitOrAssign<JsonLdProfile> for JsonLdProfileSet {
237    #[inline]
238    fn bitor_assign(&mut self, rhs: JsonLdProfile) {
239        *self |= JsonLdProfileSet::from(rhs);
240    }
241}
242
243/// JSON-LD [processing mode](https://www.w3.org/TR/json-ld11/#dfn-processing-mode)
244#[derive(Eq, PartialEq, Debug, Clone, Copy, Hash, Default)]
245pub enum JsonLdProcessingMode {
246    #[default]
247    JsonLd1_0,
248    JsonLd1_1, // TODO: Move to 1.1 when implemented
249}
250
251impl JsonLdProcessingMode {
252    /// The string identifier.
253    ///
254    /// ```
255    /// use oxirs_core::jsonld::JsonLdProcessingMode;
256    ///
257    /// assert_eq!(JsonLdProcessingMode::JsonLd1_0.as_str(), "json-ld-1.0");
258    /// ```
259    #[inline]
260    pub const fn as_str(self) -> &'static str {
261        match self {
262            JsonLdProcessingMode::JsonLd1_0 => "json-ld-1.0",
263            JsonLdProcessingMode::JsonLd1_1 => "json-ld-1.1",
264        }
265    }
266
267    /// From a string identifier.
268    ///
269    /// ```
270    /// use oxirs_core::jsonld::JsonLdProcessingMode;
271    ///
272    /// assert_eq!(
273    ///     JsonLdProcessingMode::from_id("json-ld-1.1"),
274    ///     Some(JsonLdProcessingMode::JsonLd1_1)
275    /// );
276    /// ```
277    #[inline]
278    pub fn from_id(id: &str) -> Option<Self> {
279        match id {
280            "json-ld-1.0" => Some(JsonLdProcessingMode::JsonLd1_0),
281            "json-ld-1.1" => Some(JsonLdProcessingMode::JsonLd1_1),
282            _ => None,
283        }
284    }
285}