json_ld_core/
term.rs

1use crate::{Id, ValidId};
2use contextual::{AsRefWithContext, DisplayWithContext, WithContext};
3use iref::IriBuf;
4use json_ld_syntax::Keyword;
5use rdf_types::{vocabulary::Vocabulary, BlankIdBuf};
6use std::fmt;
7
8/// Identifier, keyword or `@null`.
9#[derive(Clone, PartialEq, Eq, Hash)]
10pub enum Term<T = IriBuf, B = BlankIdBuf> {
11	/// `@null` value.
12	Null,
13
14	/// Node identifier.
15	Id(Id<T, B>),
16
17	/// Keyword.
18	Keyword(Keyword),
19}
20
21impl<I, B> Term<I, B> {
22	/// Checks if this term is `@null`.
23	pub fn is_null(&self) -> bool {
24		matches!(self, Term::Null)
25	}
26
27	/// Turns this term into an IRI if possible.
28	///
29	/// If it is not an IRI, returns the term itself.
30	pub fn into_iri(self) -> Result<I, Self> {
31		match self {
32			Term::Id(Id::Valid(ValidId::Iri(id))) => Ok(id),
33			term => Err(term),
34		}
35	}
36
37	/// Checks if this term is a keyword.
38	pub fn is_keyword(&self) -> bool {
39		matches!(self, Term::Keyword(_))
40	}
41
42	/// Returns a reference to the IRI representation of the term, if any.
43	pub fn as_iri(&self) -> Option<&I> {
44		match self {
45			Term::Id(p) => p.as_iri(),
46			_ => None,
47		}
48	}
49
50	pub fn map_id<U, C>(
51		self,
52		f: impl FnOnce(rdf_types::Id<I, B>) -> rdf_types::Id<U, C>,
53	) -> Term<U, C> {
54		match self {
55			Self::Null => Term::Null,
56			Self::Keyword(k) => Term::Keyword(k),
57			Self::Id(id) => Term::Id(id.map(f)),
58		}
59	}
60}
61
62impl<T, B, N: Vocabulary<Iri = T, BlankId = B>> DisplayWithContext<N> for Term<T, B> {
63	fn fmt_with(&self, vocabulary: &N, f: &mut fmt::Formatter) -> fmt::Result {
64		use std::fmt::Display;
65		match self {
66			Self::Null => write!(f, "null"),
67			Self::Id(id) => id.with(vocabulary).fmt(f),
68			Self::Keyword(k) => k.fmt(f),
69		}
70	}
71}
72
73impl<T: AsRef<str>, B: AsRef<str>> Term<T, B> {
74	pub fn as_str(&self) -> &str {
75		match self {
76			Term::Id(p) => p.as_str(),
77			Term::Keyword(k) => k.into_str(),
78			Term::Null => "",
79		}
80	}
81}
82
83impl<T, B, N: Vocabulary<Iri = T, BlankId = B>> AsRefWithContext<str, N> for Term<T, B> {
84	fn as_ref_with<'a>(&'a self, vocabulary: &'a N) -> &'a str {
85		match self {
86			Term::Id(p) => p.with(vocabulary).as_str(),
87			Term::Keyword(k) => k.into_str(),
88			Term::Null => "",
89		}
90	}
91}
92
93impl<'a, T, B> From<&'a Term<T, B>> for Term<&'a T, &'a B> {
94	fn from(t: &'a Term<T, B>) -> Term<&'a T, &'a B> {
95		match t {
96			Term::Null => Term::Null,
97			Term::Id(r) => Term::Id(r.into()),
98			Term::Keyword(k) => Term::Keyword(*k),
99		}
100	}
101}
102
103impl<T, B> From<T> for Term<T, B> {
104	fn from(id: T) -> Term<T, B> {
105		Term::Id(Id::Valid(ValidId::Iri(id)))
106	}
107}
108
109impl<T, B> From<Id<T, B>> for Term<T, B> {
110	fn from(prop: Id<T, B>) -> Term<T, B> {
111		Term::Id(prop)
112	}
113}
114
115impl<T: fmt::Display, B: fmt::Display> fmt::Display for Term<T, B> {
116	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
117		match self {
118			Term::Id(p) => p.fmt(f),
119			Term::Keyword(kw) => kw.fmt(f),
120			Term::Null => write!(f, "null"),
121		}
122	}
123}
124
125impl<T: fmt::Debug, B: fmt::Debug> fmt::Debug for Term<T, B> {
126	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
127		match self {
128			Term::Id(p) => write!(f, "Term::Ref({p:?})"),
129			Term::Keyword(kw) => write!(f, "Term::Keyword({kw})"),
130			Term::Null => write!(f, "Term::Null"),
131		}
132	}
133}