1use crate::{object, Direction, LangString, LenientLangTag};
2use educe::Educe;
3use iref::{Iri, IriBuf};
4use json_ld_syntax::{IntoJsonWithContext, Keyword};
5use json_syntax::{Number, NumberBuf};
6use rdf_types::vocabulary::{IriVocabulary, IriVocabularyMut};
7use std::{hash::Hash, marker::PhantomData};
8
9use super::InvalidExpandedJson;
10
11pub enum Type<T> {
13 Json,
14 Id(T),
15}
16
17impl<T> Type<T> {
18 pub fn as_id(&self) -> Option<crate::id::Ref<T>> {
19 match self {
20 Self::Json => None,
21 Self::Id(t) => Some(crate::id::Ref::Iri(t)),
22 }
23 }
24}
25
26#[derive(Educe)]
28#[educe(Clone, Copy)]
29pub enum TypeRef<'a, T> {
30 Json,
31 Id(&'a T),
32}
33
34impl<'a, T> TypeRef<'a, T> {
35 pub fn as_syntax_type(&self) -> crate::Type<&'a T> {
36 match self {
37 Self::Json => crate::Type::Json,
38 Self::Id(id) => crate::Type::Iri(id),
39 }
40 }
41
42 pub fn into_reference<B>(self) -> Option<crate::id::Ref<'a, T, B>> {
43 match self {
44 Self::Json => None,
45 Self::Id(t) => Some(crate::id::Ref::Iri(t)),
46 }
47 }
48}
49
50#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
52pub enum Literal {
53 Null,
55
56 Boolean(bool),
58
59 Number(NumberBuf),
61
62 String(json_syntax::String),
64}
65
66impl Literal {
67 #[inline(always)]
69 pub fn as_str(&self) -> Option<&str> {
70 match self {
71 Literal::String(s) => Some(s.as_ref()),
72 _ => None,
73 }
74 }
75
76 #[inline(always)]
78 pub fn as_bool(&self) -> Option<bool> {
79 match self {
80 Literal::Boolean(b) => Some(*b),
81 _ => None,
82 }
83 }
84
85 #[inline(always)]
87 pub fn as_number(&self) -> Option<&Number> {
88 match self {
89 Literal::Number(n) => Some(n),
90 _ => None,
91 }
92 }
93
94 pub fn into_json(self) -> json_syntax::Value {
95 match self {
96 Self::Null => json_syntax::Value::Null,
97 Self::Boolean(b) => json_syntax::Value::Boolean(b),
98 Self::Number(n) => json_syntax::Value::Number(n),
99 Self::String(s) => json_syntax::Value::String(s),
100 }
101 }
102
103 pub fn canonicalize_with(&mut self, buffer: &mut ryu_js::Buffer) {
107 if let Self::Number(n) = self {
108 *n = NumberBuf::from_number(n.canonical_with(buffer))
109 }
110 }
111
112 pub fn canonicalize(&mut self) {
114 let mut buffer = ryu_js::Buffer::new();
115 self.canonicalize_with(&mut buffer)
116 }
117}
118
119#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
123pub enum Value<T = IriBuf> {
124 Literal(Literal, Option<T>),
126
127 LangString(LangString),
129
130 Json(json_syntax::Value),
132}
133
134impl<T> Value<T> {
135 #[inline(always)]
137 pub fn null() -> Self {
138 Self::Literal(Literal::Null, None)
139 }
140
141 #[inline(always)]
142 pub fn as_str(&self) -> Option<&str> {
143 match self {
144 Value::Literal(lit, _) => lit.as_str(),
145 Value::LangString(str) => Some(str.as_str()),
146 Value::Json(_) => None,
147 }
148 }
149
150 #[inline(always)]
151 pub fn as_literal(&self) -> Option<(&Literal, Option<&T>)> {
152 match self {
153 Self::Literal(lit, ty) => Some((lit, ty.as_ref())),
154 _ => None,
155 }
156 }
157
158 pub fn literal_type(&self) -> Option<&T> {
159 match self {
160 Self::Literal(_, ty) => ty.as_ref(),
161 _ => None,
162 }
163 }
164
165 pub fn set_literal_type(&mut self, mut ty: Option<T>) -> Option<T> {
169 match self {
170 Self::Literal(_, old_ty) => {
171 std::mem::swap(old_ty, &mut ty);
172 ty
173 }
174 _ => None,
175 }
176 }
177
178 pub fn map_literal_type<F: FnOnce(Option<T>) -> Option<T>>(&mut self, f: F) {
182 if let Self::Literal(_, ty) = self {
183 *ty = f(ty.take())
184 }
185 }
186
187 #[inline(always)]
188 pub fn as_bool(&self) -> Option<bool> {
189 match self {
190 Value::Literal(lit, _) => lit.as_bool(),
191 _ => None,
192 }
193 }
194
195 #[inline(always)]
196 pub fn as_number(&self) -> Option<&Number> {
197 match self {
198 Value::Literal(lit, _) => lit.as_number(),
199 _ => None,
200 }
201 }
202
203 pub fn typ(&self) -> Option<TypeRef<T>> {
207 match self {
208 Value::Literal(_, Some(ty)) => Some(TypeRef::Id(ty)),
209 Value::Json(_) => Some(TypeRef::Json),
210 _ => None,
211 }
212 }
213
214 #[inline(always)]
218 pub fn language(&self) -> Option<&LenientLangTag> {
219 match self {
220 Value::LangString(tag) => tag.language(),
221 _ => None,
222 }
223 }
224
225 #[inline(always)]
229 pub fn direction(&self) -> Option<Direction> {
230 match self {
231 Value::LangString(str) => str.direction(),
232 _ => None,
233 }
234 }
235
236 #[inline(always)]
237 pub fn entries(&self) -> Entries<T> {
238 match self {
239 Self::Literal(l, ty) => Entries {
240 value: Some(ValueEntryRef::Literal(l)),
241 type_: ty.as_ref().map(TypeRef::Id),
242 language: None,
243 direction: None,
244 },
245 Self::LangString(l) => Entries {
246 value: Some(ValueEntryRef::LangString(l.as_str())),
247 type_: None,
248 language: l.language(),
249 direction: l.direction(),
250 },
251 Self::Json(j) => Entries {
252 value: Some(ValueEntryRef::Json(j)),
253 type_: Some(TypeRef::Json),
254 language: None,
255 direction: None,
256 },
257 }
258 }
259
260 pub(crate) fn try_from_json_object_in(
261 vocabulary: &mut impl IriVocabularyMut<Iri = T>,
262 mut object: json_syntax::Object,
263 value_entry: json_syntax::object::Entry,
264 ) -> Result<Self, InvalidExpandedJson> {
265 match object
266 .remove_unique("@type")
267 .map_err(InvalidExpandedJson::duplicate_key)?
268 {
269 Some(type_entry) => match type_entry.value {
270 json_syntax::Value::String(ty) => match ty.as_str() {
271 "@json" => Ok(Self::Json(value_entry.value)),
272 iri => match Iri::new(iri) {
273 Ok(iri) => {
274 let ty = vocabulary.insert(iri);
275 let lit = value_entry.value.try_into()?;
276 Ok(Self::Literal(lit, Some(ty)))
277 }
278 Err(_) => Err(InvalidExpandedJson::InvalidValueType),
279 },
280 },
281 _ => Err(InvalidExpandedJson::InvalidValueType),
282 },
283 None => {
284 let language = object
285 .remove_unique("@language")
286 .map_err(InvalidExpandedJson::duplicate_key)?
287 .map(json_syntax::object::Entry::into_value);
288 let direction = object
289 .remove_unique("@direction")
290 .map_err(InvalidExpandedJson::duplicate_key)?
291 .map(json_syntax::object::Entry::into_value);
292
293 if language.is_some() || direction.is_some() {
294 Ok(Self::LangString(LangString::try_from_json(
295 object,
296 value_entry.value,
297 language,
298 direction,
299 )?))
300 } else {
301 let lit = value_entry.value.try_into()?;
302 Ok(Self::Literal(lit, None))
303 }
304 }
305 }
306 }
307
308 pub fn canonicalize_with(&mut self, buffer: &mut ryu_js::Buffer) {
313 match self {
314 Self::Json(json) => json.canonicalize_with(buffer),
315 Self::Literal(l, _) => l.canonicalize_with(buffer),
316 Self::LangString(_) => (),
317 }
318 }
319
320 pub fn canonicalize(&mut self) {
322 let mut buffer = ryu_js::Buffer::new();
323 self.canonicalize_with(&mut buffer)
324 }
325
326 pub fn map_ids<U>(self, map_iri: impl FnOnce(T) -> U) -> Value<U> {
328 match self {
329 Self::Literal(l, type_) => Value::Literal(l, type_.map(map_iri)),
330 Self::LangString(s) => Value::LangString(s),
331 Self::Json(json) => Value::Json(json),
332 }
333 }
334}
335
336impl TryFrom<json_syntax::Value> for Literal {
337 type Error = InvalidExpandedJson;
338
339 fn try_from(value: json_syntax::Value) -> Result<Self, Self::Error> {
340 match value {
341 json_syntax::Value::Null => Ok(Self::Null),
342 json_syntax::Value::Boolean(b) => Ok(Self::Boolean(b)),
343 json_syntax::Value::Number(n) => Ok(Self::Number(n)),
344 json_syntax::Value::String(s) => Ok(Self::String(s)),
345 _ => Err(InvalidExpandedJson::InvalidLiteral),
346 }
347 }
348}
349
350impl<T, B> object::Any<T, B> for Value<T> {
351 #[inline(always)]
352 fn as_ref(&self) -> object::Ref<T, B> {
353 object::Ref::Value(self)
354 }
355}
356
357#[derive(Educe)]
358#[educe(Clone, Copy)]
359pub enum EntryRef<'a, T> {
360 Value(ValueEntryRef<'a>),
361 Type(TypeRef<'a, T>),
362 Language(&'a LenientLangTag),
363 Direction(Direction),
364}
365
366impl<'a, T> EntryRef<'a, T> {
367 pub fn into_key(self) -> EntryKey {
368 match self {
369 Self::Value(_) => EntryKey::Value,
370 Self::Type(_) => EntryKey::Type,
371 Self::Language(_) => EntryKey::Language,
372 Self::Direction(_) => EntryKey::Direction,
373 }
374 }
375
376 pub fn key(&self) -> EntryKey {
377 self.into_key()
378 }
379
380 pub fn into_value(self) -> EntryValueRef<'a, T> {
381 match self {
382 Self::Value(v) => EntryValueRef::Value(v),
383 Self::Type(v) => EntryValueRef::Type(v),
384 Self::Language(v) => EntryValueRef::Language(v),
385 Self::Direction(v) => EntryValueRef::Direction(v),
386 }
387 }
388
389 pub fn value(&self) -> EntryValueRef<'a, T> {
390 match self {
391 Self::Value(v) => EntryValueRef::Value(*v),
392 Self::Type(v) => EntryValueRef::Type(*v),
393 Self::Language(v) => EntryValueRef::Language(v),
394 Self::Direction(v) => EntryValueRef::Direction(*v),
395 }
396 }
397}
398
399#[derive(Educe)]
400#[educe(Clone, Copy)]
401pub enum EntryValueRef<'a, T> {
402 Value(ValueEntryRef<'a>),
403 Type(TypeRef<'a, T>),
404 Language(&'a LenientLangTag),
405 Direction(Direction),
406}
407pub enum ValueEntryRef<'a> {
408 Literal(&'a Literal),
409 LangString(&'a str),
410 Json(&'a json_syntax::Value),
411}
412
413impl<'a> Clone for ValueEntryRef<'a> {
414 fn clone(&self) -> Self {
415 *self
416 }
417}
418
419impl<'a> Copy for ValueEntryRef<'a> {}
420
421#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
422pub enum EntryKey {
423 Value,
424 Type,
425 Language,
426 Direction,
427}
428
429impl EntryKey {
430 pub fn into_keyword(self) -> Keyword {
431 match self {
432 Self::Value => Keyword::Value,
433 Self::Type => Keyword::Type,
434 Self::Language => Keyword::Language,
435 Self::Direction => Keyword::Direction,
436 }
437 }
438
439 pub fn as_keyword(&self) -> Keyword {
440 self.into_keyword()
441 }
442
443 pub fn into_str(&self) -> &'static str {
444 match self {
445 Self::Value => "@value",
446 Self::Type => "@type",
447 Self::Language => "@language",
448 Self::Direction => "@direction",
449 }
450 }
451
452 pub fn as_str(&self) -> &'static str {
453 self.into_str()
454 }
455}
456
457#[derive(Educe)]
458#[educe(Clone)]
459pub struct Entries<'a, T> {
460 value: Option<ValueEntryRef<'a>>,
461 type_: Option<TypeRef<'a, T>>,
462 language: Option<&'a LenientLangTag>,
463 direction: Option<Direction>,
464}
465
466impl<'a, T> Iterator for Entries<'a, T> {
467 type Item = EntryRef<'a, T>;
468
469 fn size_hint(&self) -> (usize, Option<usize>) {
470 let mut len = 0;
471
472 if self.value.is_some() {
473 len += 1
474 }
475
476 if self.type_.is_some() {
477 len += 1
478 }
479
480 if self.language.is_some() {
481 len += 1
482 }
483
484 if self.direction.is_some() {
485 len += 1
486 }
487
488 (len, Some(len))
489 }
490
491 fn next(&mut self) -> Option<Self::Item> {
492 self.value.take().map(EntryRef::Value).or_else(|| {
493 self.type_.take().map(EntryRef::Type).or_else(|| {
494 self.language
495 .take()
496 .map(EntryRef::Language)
497 .or_else(|| self.direction.take().map(EntryRef::Direction))
498 })
499 })
500 }
501}
502
503impl<'a, T> ExactSizeIterator for Entries<'a, T> {}
504
505impl<'a, T> DoubleEndedIterator for Entries<'a, T> {
506 fn next_back(&mut self) -> Option<Self::Item> {
507 self.direction.take().map(EntryRef::Direction).or_else(|| {
508 self.language.take().map(EntryRef::Language).or_else(|| {
509 self.type_
510 .take()
511 .map(EntryRef::Type)
512 .or_else(|| self.value.take().map(EntryRef::Value))
513 })
514 })
515 }
516}
517
518pub enum FragmentRef<'a, T> {
520 Entry(EntryRef<'a, T>),
522
523 Key(EntryKey),
525
526 Value(EntryValueRef<'a, T>),
528
529 JsonFragment(json_syntax::FragmentRef<'a>),
531}
532
533impl<'a, T> FragmentRef<'a, T> {
534 pub fn into_iri(self) -> Option<&'a T> {
535 match self {
536 Self::Value(EntryValueRef::Type(TypeRef::Id(id))) => Some(id),
537 _ => None,
538 }
539 }
540
541 pub fn as_iri(&self) -> Option<&'a T> {
542 match self {
543 Self::Value(EntryValueRef::Type(TypeRef::Id(id))) => Some(id),
544 _ => None,
545 }
546 }
547
548 pub fn is_json_array(&self) -> bool {
549 match self {
550 Self::Value(EntryValueRef::Value(ValueEntryRef::Json(json))) => json.is_array(),
551 Self::JsonFragment(json) => json.is_array(),
552 _ => false,
553 }
554 }
555
556 pub fn is_json_object(&self) -> bool {
557 match self {
558 Self::Value(EntryValueRef::Value(ValueEntryRef::Json(json))) => json.is_object(),
559 Self::JsonFragment(json) => json.is_object(),
560 _ => false,
561 }
562 }
563
564 pub fn sub_fragments(&self) -> SubFragments<'a, T> {
565 match self {
566 Self::Entry(e) => SubFragments::Entry(Some(e.key()), Some(e.value())),
567 Self::Value(EntryValueRef::Value(ValueEntryRef::Json(json))) => match json {
568 json_syntax::Value::Array(a) => {
569 SubFragments::JsonFragment(json_syntax::SubFragments::Array(a.iter()))
570 }
571 json_syntax::Value::Object(o) => {
572 SubFragments::JsonFragment(json_syntax::SubFragments::Object(o.iter()))
573 }
574 _ => SubFragments::None(PhantomData),
575 },
576 Self::JsonFragment(f) => SubFragments::JsonFragment(f.sub_fragments()),
577 _ => SubFragments::None(PhantomData),
578 }
579 }
580}
581
582pub enum SubFragments<'a, T> {
583 None(PhantomData<T>),
584 Entry(Option<EntryKey>, Option<EntryValueRef<'a, T>>),
585 JsonFragment(json_syntax::SubFragments<'a>),
586}
587
588impl<'a, T: 'a> Iterator for SubFragments<'a, T> {
589 type Item = FragmentRef<'a, T>;
590
591 fn next(&mut self) -> Option<Self::Item> {
592 match self {
593 Self::None(_) => None,
594 Self::Entry(k, v) => k
595 .take()
596 .map(FragmentRef::Key)
597 .or_else(|| v.take().map(FragmentRef::Value)),
598 Self::JsonFragment(f) => f.next().map(|v| FragmentRef::JsonFragment(v)),
599 }
600 }
601}
602
603impl<T, N: IriVocabulary<Iri = T>> IntoJsonWithContext<N> for Value<T> {
604 fn into_json_with(self, vocabulary: &N) -> json_syntax::Value {
605 let mut obj = json_syntax::Object::new();
606
607 let value = match self {
608 Self::Literal(lit, ty) => {
609 if let Some(ty) = ty {
610 obj.insert("@type".into(), vocabulary.iri(&ty).unwrap().as_str().into());
611 }
612
613 lit.into_json()
614 }
615 Self::LangString(s) => {
616 if let Some(language) = s.language() {
617 obj.insert("@language".into(), language.as_str().into());
618 }
619
620 if let Some(direction) = s.direction() {
621 obj.insert("@direction".into(), direction.as_str().into());
622 }
623
624 s.as_str().into()
625 }
626 Self::Json(json) => {
627 obj.insert("@type".into(), "@json".into());
628
629 json
630 }
631 };
632
633 obj.insert("@value".into(), value);
634 obj.into()
635 }
636}