srdf/
srdf_basic.rs

1use std::fmt::Debug;
2use std::fmt::Display;
3use std::hash::Hash;
4
5use iri_s::IriS;
6use oxrdf::BlankNode as OxBlankNode;
7use oxrdf::Literal as OxLiteral;
8use oxrdf::NamedNode as OxNamedNode;
9use oxrdf::Subject as OxSubject;
10use oxrdf::SubjectRef;
11use oxrdf::Term as OxTerm;
12use oxrdf::Triple as OxTriple;
13use prefixmap::PrefixMap;
14use prefixmap::PrefixMapError;
15use rust_decimal::Decimal;
16
17use crate::lang::Lang;
18use crate::literal::Literal as SRDFLiteral;
19use crate::matcher::Matcher;
20use crate::Object;
21
22pub trait Rdf: Sized {
23    type Subject: Subject
24        + From<Self::IRI>
25        + From<Self::BNode>
26        + From<IriS>
27        + TryFrom<Self::Term>
28        + TryFrom<Object>
29        + Matcher<Self::Subject>;
30
31    type IRI: Iri + From<IriS> + TryFrom<Self::Term> + Matcher<Self::IRI>;
32
33    type Term: Term
34        + From<Self::Subject>
35        + From<Self::IRI>
36        + From<Self::BNode>
37        + From<Self::Literal>
38        + From<IriS>
39        + From<Object>
40        + Into<Object>
41        + Matcher<Self::Term>;
42
43    type BNode: BlankNode + TryFrom<Self::Term>;
44
45    type Literal: Literal
46        + From<bool>
47        + From<String>
48        + From<i128>
49        + From<f64>
50        + TryFrom<Self::Term>
51        + From<SRDFLiteral>;
52
53    type Triple: Triple<Self::Subject, Self::IRI, Self::Term>;
54
55    type Err: Display;
56
57    fn qualify_iri(&self, iri: &Self::IRI) -> String;
58    fn qualify_subject(&self, subj: &Self::Subject) -> String;
59    fn qualify_term(&self, term: &Self::Term) -> String;
60
61    fn prefixmap(&self) -> Option<PrefixMap>;
62
63    /// Resolves a a prefix and a local name and obtains the corresponding full `IriS`
64    fn resolve_prefix_local(&self, prefix: &str, local: &str) -> Result<IriS, PrefixMapError>;
65}
66
67#[derive(PartialEq)]
68pub enum TermKind {
69    Iri,
70    BlankNode,
71    Literal,
72    Triple,
73}
74
75pub trait Subject: Debug + Display + PartialEq + Clone + Eq + Hash {
76    fn kind(&self) -> TermKind;
77
78    fn is_iri(&self) -> bool {
79        self.kind() == TermKind::Iri
80    }
81
82    fn is_blank_node(&self) -> bool {
83        self.kind() == TermKind::BlankNode
84    }
85
86    fn is_triple(&self) -> bool {
87        self.kind() == TermKind::Triple
88    }
89}
90
91impl Subject for OxSubject {
92    fn kind(&self) -> TermKind {
93        match self {
94            OxSubject::NamedNode(_) => TermKind::Iri,
95            OxSubject::BlankNode(_) => TermKind::BlankNode,
96            #[cfg(feature = "rdf-star")]
97            OxSubject::Triple(_) => TermKind::Triple,
98        }
99    }
100}
101
102impl Subject for SubjectRef<'_> {
103    fn kind(&self) -> TermKind {
104        match self {
105            SubjectRef::NamedNode(_) => TermKind::Iri,
106            SubjectRef::BlankNode(_) => TermKind::BlankNode,
107            #[cfg(feature = "rdf-star")]
108            SubjectRef::Triple(_) => TermKind::Triple,
109        }
110    }
111}
112
113impl Matcher<OxSubject> for OxSubject {
114    fn value(&self) -> Option<OxSubject> {
115        Some(self.clone())
116    }
117}
118
119pub trait Iri: Debug + Display + Hash + Eq + Ord + Clone {
120    fn as_str(&self) -> &str;
121}
122
123impl Iri for OxNamedNode {
124    fn as_str(&self) -> &str {
125        self.as_str()
126    }
127}
128
129impl Matcher<OxNamedNode> for OxNamedNode {
130    fn value(&self) -> Option<OxNamedNode> {
131        Some(self.clone())
132    }
133}
134
135pub trait Term: Debug + Clone + Display + PartialEq + Eq + Hash {
136    fn kind(&self) -> TermKind;
137
138    fn is_iri(&self) -> bool {
139        self.kind() == TermKind::Iri
140    }
141
142    fn is_blank_node(&self) -> bool {
143        self.kind() == TermKind::BlankNode
144    }
145
146    fn is_literal(&self) -> bool {
147        self.kind() == TermKind::Literal
148    }
149
150    fn is_triple(&self) -> bool {
151        self.kind() == TermKind::Triple
152    }
153}
154
155impl Term for OxTerm {
156    fn kind(&self) -> TermKind {
157        match self {
158            OxTerm::NamedNode(_) => TermKind::Iri,
159            OxTerm::BlankNode(_) => TermKind::BlankNode,
160            OxTerm::Literal(_) => TermKind::Literal,
161            #[cfg(feature = "rdf-star")]
162            OxTerm::Triple(_) => TermKind::Triple,
163        }
164    }
165}
166
167impl Matcher<OxTerm> for OxTerm {
168    fn value(&self) -> Option<OxTerm> {
169        Some(self.clone())
170    }
171}
172
173pub trait Literal: Debug + Clone + Display + PartialEq + Eq + Hash {
174    fn lexical_form(&self) -> &str;
175
176    fn lang(&self) -> Option<&str>;
177
178    fn datatype(&self) -> &str;
179
180    fn as_bool(&self) -> Option<bool> {
181        match self.lexical_form() {
182            "true" => Some(true),
183            "false" => Some(false),
184            _ => None,
185        }
186    }
187
188    fn as_integer(&self) -> Option<isize> {
189        self.lexical_form().parse().ok()
190    }
191
192    fn as_double(&self) -> Option<f64> {
193        self.lexical_form().parse().ok()
194    }
195
196    fn as_decimal(&self) -> Option<Decimal> {
197        self.lexical_form().parse().ok()
198    }
199
200    fn as_literal(&self) -> SRDFLiteral {
201        if let Some(bool) = self.as_bool() {
202            SRDFLiteral::boolean(bool)
203        } else if let Some(int) = self.as_integer() {
204            SRDFLiteral::integer(int)
205        } else if let Some(decimal) = self.as_double() {
206            SRDFLiteral::double(decimal)
207        } else if let Some(decimal) = self.as_decimal() {
208            SRDFLiteral::decimal(decimal)
209        } else if let Some(lang) = self.lang() {
210            SRDFLiteral::lang_str(self.lexical_form(), Lang::new_unchecked(lang))
211        } else {
212            SRDFLiteral::str(self.lexical_form())
213        }
214    }
215}
216
217impl Literal for OxLiteral {
218    fn lexical_form(&self) -> &str {
219        self.value()
220    }
221
222    fn lang(&self) -> Option<&str> {
223        self.language()
224    }
225
226    fn datatype(&self) -> &str {
227        self.datatype().as_str()
228    }
229}
230
231pub trait BlankNode: Debug + Display + PartialEq {
232    fn new(id: impl Into<String>) -> Self;
233    fn id(&self) -> &str;
234}
235
236impl BlankNode for OxBlankNode {
237    fn new(id: impl Into<String>) -> Self {
238        OxBlankNode::new_unchecked(id)
239    }
240
241    fn id(&self) -> &str {
242        self.as_str()
243    }
244}
245
246pub trait Triple<S, P, O>: Debug + Clone + Display
247where
248    S: Subject,
249    P: Iri,
250    O: Term,
251{
252    fn new(subj: impl Into<S>, pred: impl Into<P>, obj: impl Into<O>) -> Self;
253
254    fn subj(&self) -> S;
255    fn pred(&self) -> P;
256    fn obj(&self) -> O;
257
258    fn into_components(self) -> (S, P, O);
259
260    fn into_subject(self) -> S {
261        self.into_components().0
262    }
263
264    fn into_predicate(self) -> P {
265        self.into_components().1
266    }
267
268    fn into_object(self) -> O {
269        self.into_components().2
270    }
271}
272
273impl Triple<OxSubject, OxNamedNode, OxTerm> for OxTriple {
274    fn new(
275        subj: impl Into<OxSubject>,
276        pred: impl Into<OxNamedNode>,
277        obj: impl Into<OxTerm>,
278    ) -> Self {
279        OxTriple::new(subj, pred, obj)
280    }
281
282    fn subj(&self) -> OxSubject {
283        self.subject.clone()
284    }
285
286    fn pred(&self) -> OxNamedNode {
287        self.predicate.clone()
288    }
289
290    fn obj(&self) -> OxTerm {
291        self.object.clone()
292    }
293
294    fn into_components(self) -> (OxSubject, OxNamedNode, OxTerm) {
295        (self.subject, self.predicate, self.object)
296    }
297}