Skip to main content

rudof_rdf/rdf_impl/
oxrdf_impl.rs

1use crate::rdf_core::{
2    Matcher,
3    term::{
4        BlankNode, Iri, Subject, Term, TermKind, Triple,
5        literal::{ConcreteLiteral, Lang, Literal},
6    },
7};
8use iri_s::IriS;
9use oxrdf::{
10    BlankNode as OxBlankNode, Literal as OxLiteral, NamedNode as OxNamedNode, NamedOrBlankNode as OxSubject,
11    NamedOrBlankNodeRef as OxSubjectRef, Term as OxTerm, Triple as OxTriple,
12};
13use prefixmap::IriRef;
14
15/// Implements the `Subject` trait for `OxSubject` (owned version).
16///
17/// This allows owned `NamedOrBlankNode` instances from `oxrdf` to be used
18/// as RDF subjects in the core trait system.
19impl Subject for OxSubject {
20    /// Returns the kind of term this subject represents.
21    ///
22    /// # Returns
23    /// - `TermKind::Iri` for named nodes (IRIs)
24    /// - `TermKind::BlankNode` for blank nodes
25    fn kind(&self) -> TermKind {
26        match self {
27            OxSubject::NamedNode(_) => TermKind::Iri,
28            OxSubject::BlankNode(_) => TermKind::BlankNode,
29        }
30    }
31}
32
33/// Implements the `Subject` trait for `OxSubjectRef` (borrowed version).
34///
35/// This allows borrowed `NamedOrBlankNodeRef` instances from `oxrdf` to be
36/// used as RDF subjects without requiring ownership.
37impl Subject for OxSubjectRef<'_> {
38    /// Returns the kind of term this subject reference represents.
39    ///
40    /// # Returns
41    /// - `TermKind::Iri` for named nodes (IRIs)
42    /// - `TermKind::BlankNode` for blank nodes
43    fn kind(&self) -> TermKind {
44        match self {
45            OxSubjectRef::NamedNode(_) => TermKind::Iri,
46            OxSubjectRef::BlankNode(_) => TermKind::BlankNode,
47        }
48    }
49}
50
51/// Implements the `Iri` trait for `OxNamedNode`.
52///
53/// Provides access to the string representation of an IRI from an `oxrdf`
54/// named node.
55impl Iri for OxNamedNode {
56    /// Returns the IRI as a string slice.
57    fn as_str(&self) -> &str {
58        self.as_str()
59    }
60}
61
62/// Implements the `Term` trait for `OxTerm`.
63///
64/// This is the main implementation for RDF terms, supporting IRIs, blank nodes,
65/// literals, and RDF-star quoted triples.
66impl Term for OxTerm {
67    /// Returns the kind of RDF term.
68    ///
69    /// # Returns
70    /// - `TermKind::Iri` for named nodes
71    /// - `TermKind::BlankNode` for blank nodes
72    /// - `TermKind::Literal` for literal values
73    /// - `TermKind::Triple` for RDF-star quoted triples
74    fn kind(&self) -> TermKind {
75        match self {
76            OxTerm::NamedNode(_) => TermKind::Iri,
77            OxTerm::BlankNode(_) => TermKind::BlankNode,
78            OxTerm::Literal(_) => TermKind::Literal,
79            OxTerm::Triple(_) => TermKind::Triple,
80        }
81    }
82
83    // Returns the lexical form of this term as an owned string.
84    /// # Returns
85    /// - For IRIs: the full IRI string
86    /// - For blank nodes: the blank node identifier (e.g., "_:b0")
87    /// - For literals: the literal value without datatype or language tag
88    /// - For triples: the string representation of the entire triple
89    fn lexical_form(&self) -> String {
90        match self {
91            OxTerm::NamedNode(iri) => iri.as_str().to_string(),
92            OxTerm::BlankNode(bnode) => bnode.as_str().to_string(),
93            OxTerm::Literal(literal) => literal.value().to_string(),
94            OxTerm::Triple(triple) => triple.to_string(),
95        }
96    }
97}
98
99/// Implements the `Matcher` trait for `OxNamedNode`, enabling pattern matching.
100///
101/// This trivial implementation always matches by cloning the named node.
102impl Matcher<OxNamedNode> for OxNamedNode {
103    /// Always returns `Some(self)` indicating a successful match.
104    fn value(&self) -> Option<&OxNamedNode> {
105        Some(self)
106    }
107}
108
109/// Implements the `Matcher` trait for `OxSubject`, enabling pattern matching.
110impl Matcher<OxSubject> for OxSubject {
111    /// Always returns `Some(self)` indicating a successful match.
112    fn value(&self) -> Option<&OxSubject> {
113        Some(self)
114    }
115}
116
117/// Implements the `Matcher` trait for `OxTerm`, enabling pattern matching.
118impl Matcher<OxTerm> for OxTerm {
119    /// Always returns `Some(self)` indicating a successful match.
120    fn value(&self) -> Option<&OxTerm> {
121        Some(self)
122    }
123}
124
125/// Implements the `Literal` trait for `OxLiteral`.
126///
127/// Provides access to literal values, language tags, and datatypes from
128/// `oxrdf` literals.
129impl Literal for OxLiteral {
130    /// Returns the lexical form of the literal as a string slice.
131    fn lexical_form(&self) -> &str {
132        self.value()
133    }
134
135    /// Returns the language tag if this is a language-tagged string.
136    ///
137    /// # Returns
138    /// - `Some(Lang)` if this literal has a language tag (e.g., "en", "es")
139    /// - `None` if this literal is not language-tagged
140    fn lang(&self) -> Option<Lang> {
141        self.language().and_then(|lang| Lang::new(lang).ok())
142    }
143
144    /// Returns the datatype IRI of this literal.
145    fn datatype(&self) -> IriRef {
146        IriRef::iri(IriS::new_unchecked(self.datatype().as_str()))
147    }
148
149    /// Attempts to convert this literal to a concrete typed value.
150    ///
151    /// # Returns
152    /// `Some(ConcreteLiteral)` if the literal can be parsed into a concrete type,
153    /// `None` otherwise.
154    fn to_concrete_literal(&self) -> Option<ConcreteLiteral> {
155        todo!()
156    }
157}
158
159/// Implements the `BlankNode` trait for `OxBlankNode`.
160///
161/// Provides construction and access to blank node identifiers.
162impl BlankNode for OxBlankNode {
163    /// Creates a new blank node with the given identifier.
164    ///
165    /// # Parameters
166    /// - `id`: The blank node identifier (converted to `String`)
167    fn new(id: impl Into<String>) -> Self {
168        OxBlankNode::new_unchecked(id)
169    }
170
171    /// Returns the identifier of this blank node.
172    fn id(&self) -> &str {
173        self.as_str()
174    }
175}
176
177/// Implements the `Triple` trait for `OxTriple`.
178///
179/// Provides construction, field access, and decomposition for RDF triples
180/// consisting of subject, predicate, and object.
181impl Triple<OxSubject, OxNamedNode, OxTerm> for OxTriple {
182    /// Creates a new RDF triple from subject, predicate, and object.
183    ///
184    /// # Parameters
185    /// - `subj`: The subject (IRI or blank node)
186    /// - `pred`: The predicate (IRI/named node)
187    /// - `obj`: The object (IRI, blank node, literal, or quoted triple)
188    fn new(subj: impl Into<OxSubject>, pred: impl Into<OxNamedNode>, obj: impl Into<OxTerm>) -> Self {
189        OxTriple::new(subj, pred, obj)
190    }
191
192    /// Returns a reference to the subject of this triple.
193    fn subj(&self) -> &OxSubject {
194        &self.subject
195    }
196
197    /// Returns a reference to the predicate of this triple.
198    fn pred(&self) -> &OxNamedNode {
199        &self.predicate
200    }
201
202    /// Returns a reference to the object of this triple.
203    fn obj(&self) -> &OxTerm {
204        &self.object
205    }
206
207    /// Consumes the triple and returns its components.
208    ///
209    /// This method is useful when you need owned values rather than references,
210    /// avoiding additional clones.
211    fn into_components(self) -> (OxSubject, OxNamedNode, OxTerm) {
212        (self.subject, self.predicate, self.object)
213    }
214}