rio_api/
generalized.rs

1//! This module contains extensions for generalized RDF / RDF-star.
2//! Its elements are re-exported by `model` and `parser`, respectively.
3
4/// Data structures for generalized [RDF 1.1 Concepts](https://www.w3.org/TR/rdf11-concepts/),
5/// allowing variables, and any kind of node in any Triple/Quad position.
6pub mod model {
7    use std::convert::TryFrom;
8    use std::error::Error;
9    use std::fmt;
10
11    pub use crate::model::*;
12
13    /// A SPARQL [variable](https://www.w3.org/TR/sparql11-query/#QSynVariables).
14    ///
15    /// The default string formatter is returning a SPARQL compatible representation.
16    ///
17    /// ```
18    /// use rio_api::model::Variable;
19    ///
20    /// assert_eq!(
21    ///     "?foobar",
22    ///     Variable { name: "foobar" }.to_string()
23    /// )
24    /// ```
25    ///
26    /// Using it requires to enable the `generalized` feature.
27    #[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Copy, Hash)]
28    pub struct Variable<'a> {
29        /// The name of  the [variable](https://www.w3.org/TR/sparql11-query/#QSynVariables) itself.
30        pub name: &'a str,
31    }
32
33    impl<'a> fmt::Display for Variable<'a> {
34        #[inline]
35        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36            write!(f, "?{}", self.name)
37        }
38    }
39
40    //
41
42    /// A generalized RDF [term](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-term).
43    ///
44    /// It is the union of
45    /// * [IRI](https://www.w3.org/TR/rdf11-concepts/#dfn-iri) references (absolute *or relative*),
46    /// * [blank nodes](https://www.w3.org/TR/rdf11-concepts/#dfn-blank-node)
47    /// * [literals](https://www.w3.org/TR/rdf11-concepts/#dfn-literal) and
48    /// * [variables](https://www.w3.org/TR/sparql11-query/#QSynVariables).
49    /// * [quoted triples](https://www.w3.org/2021/12/rdf-star.html#dfn-quoted)
50    ///
51    /// The default string formatter is returning an N-Triples, Turtle and SPARQL compatible representation.
52    ///
53    /// Using it requires to enable the `generalized` feature.
54    #[derive(Eq, PartialEq, Debug, Clone, Copy, Hash)]
55    pub enum GeneralizedTerm<'a> {
56        NamedNode(NamedNode<'a>),
57        BlankNode(BlankNode<'a>),
58        Literal(Literal<'a>),
59        Variable(Variable<'a>),
60        Triple(&'a [GeneralizedTerm<'a>; 3]),
61    }
62
63    impl<'a> From<NamedNode<'a>> for GeneralizedTerm<'a> {
64        #[inline]
65        fn from(other: NamedNode<'a>) -> GeneralizedTerm<'a> {
66            GeneralizedTerm::NamedNode(other)
67        }
68    }
69
70    impl<'a> From<BlankNode<'a>> for GeneralizedTerm<'a> {
71        #[inline]
72        fn from(other: BlankNode<'a>) -> GeneralizedTerm<'a> {
73            GeneralizedTerm::BlankNode(other)
74        }
75    }
76
77    impl<'a> From<Literal<'a>> for GeneralizedTerm<'a> {
78        #[inline]
79        fn from(other: Literal<'a>) -> GeneralizedTerm<'a> {
80            GeneralizedTerm::Literal(other)
81        }
82    }
83
84    impl<'a> From<Variable<'a>> for GeneralizedTerm<'a> {
85        #[inline]
86        fn from(other: Variable<'a>) -> GeneralizedTerm<'a> {
87            GeneralizedTerm::Variable(other)
88        }
89    }
90
91    impl<'a> From<GraphName<'a>> for GeneralizedTerm<'a> {
92        #[inline]
93        fn from(other: GraphName<'a>) -> GeneralizedTerm<'a> {
94            match other {
95                GraphName::NamedNode(inner) => GeneralizedTerm::NamedNode(inner),
96                GraphName::BlankNode(inner) => GeneralizedTerm::BlankNode(inner),
97            }
98        }
99    }
100
101    impl<'a> TryFrom<GeneralizedTerm<'a>> for NamedNode<'a> {
102        type Error = StrictRdfError;
103
104        #[inline]
105        fn try_from(other: GeneralizedTerm<'a>) -> Result<NamedNode<'a>, StrictRdfError> {
106            match other {
107                GeneralizedTerm::NamedNode(inner) => Ok(inner),
108                GeneralizedTerm::BlankNode(_) => Err(StrictRdfError {
109                    message: "Blank node cannot be used as predicate",
110                }),
111                GeneralizedTerm::Literal(_) => Err(StrictRdfError {
112                    message: "Literal cannot be used as predicate",
113                }),
114                GeneralizedTerm::Variable(_) => Err(StrictRdfError {
115                    message: "Variable cannot be converted to Term",
116                }),
117                GeneralizedTerm::Triple(_) => Err(StrictRdfError {
118                    message: "Triple cannot be used as predicate",
119                }),
120            }
121        }
122    }
123
124    impl<'a> TryFrom<GeneralizedTerm<'a>> for GraphName<'a> {
125        type Error = StrictRdfError;
126
127        #[inline]
128        fn try_from(other: GeneralizedTerm<'a>) -> Result<GraphName<'a>, StrictRdfError> {
129            match other {
130                GeneralizedTerm::NamedNode(inner) => Ok(GraphName::NamedNode(inner)),
131                GeneralizedTerm::BlankNode(inner) => Ok(GraphName::BlankNode(inner)),
132                GeneralizedTerm::Literal(_) => Err(StrictRdfError {
133                    message: "Literal cannot be used a graph name",
134                }),
135                GeneralizedTerm::Variable(_) => Err(StrictRdfError {
136                    message: "Variable cannot be converted to Term",
137                }),
138                GeneralizedTerm::Triple(_) => Err(StrictRdfError {
139                    message: "Triple cannot be used as a graph name",
140                }),
141            }
142        }
143    }
144
145    impl<'a> fmt::Display for GeneralizedTerm<'a> {
146        #[inline]
147        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
148            match self {
149                GeneralizedTerm::NamedNode(node) => node.fmt(f),
150                GeneralizedTerm::BlankNode(node) => node.fmt(f),
151                GeneralizedTerm::Literal(literal) => literal.fmt(f),
152                GeneralizedTerm::Variable(variable) => variable.fmt(f),
153                GeneralizedTerm::Triple(triple) => {
154                    write!(f, "<< {} {} {} >>", triple[0], triple[1], triple[2])
155                }
156            }
157        }
158    }
159
160    //
161
162    /// A generalized [RDF triple](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-triple) in a [RDF dataset](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-dataset).
163    ///
164    /// The default string formatter is returning a SPARQL representation.
165    ///
166    /// ```
167    /// use rio_api::model::{GeneralizedQuad, Variable};
168    ///
169    /// assert_eq!(
170    ///     "?s ?p ?o .",
171    ///     GeneralizedQuad {
172    ///         subject: Variable { name: "s" }.into(),
173    ///         predicate: Variable { name: "p" }.into(),
174    ///         object: Variable { name: "o" }.into(),
175    ///         graph_name: None,
176    ///     }.to_string()
177    /// );
178    ///
179    /// assert_eq!(
180    ///     "GRAPH ?g { ?s ?p ?o .}",
181    ///     GeneralizedQuad {
182    ///         subject: Variable { name: "s" }.into(),
183    ///         predicate: Variable { name: "p" }.into(),
184    ///         object: Variable { name: "o" }.into(),
185    ///         graph_name: Some(Variable { name: "g" }.into()),
186    ///     }.to_string()
187    /// );
188    /// ```
189    ///
190    /// Using it requires to enable the `generalized` feature.
191    #[derive(Eq, PartialEq, Debug, Clone, Hash)]
192    pub struct GeneralizedQuad<'a> {
193        pub subject: GeneralizedTerm<'a>,
194        pub predicate: GeneralizedTerm<'a>,
195        pub object: GeneralizedTerm<'a>,
196        pub graph_name: Option<GeneralizedTerm<'a>>,
197    }
198
199    impl<'a> fmt::Display for GeneralizedQuad<'a> {
200        #[inline]
201        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
202            if let Some(graph_name) = &self.graph_name {
203                write!(f, "GRAPH {} {{ ", graph_name)?;
204            }
205            write!(f, "{} {} {} .", self.subject, self.predicate, self.object)?;
206            if self.graph_name.is_some() {
207                write!(f, "}}")?;
208            }
209            Ok(())
210        }
211    }
212
213    //
214
215    /// An error raised when generalized RDF cannot be converted to strict RDF.
216    #[derive(Debug, Clone, Copy)]
217    pub struct StrictRdfError {
218        pub message: &'static str,
219    }
220
221    impl fmt::Display for StrictRdfError {
222        #[inline]
223        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
224            self.message.fmt(f)
225        }
226    }
227
228    impl Error for StrictRdfError {}
229}
230
231/// Interface for generalized RDF parsers.
232pub mod parser {
233    use super::model::GeneralizedQuad;
234    use std::error::Error;
235
236    /// A parser returning generalized [`Quad`](super::model::Quad).
237    ///
238    /// Using it requires to enable the `generalized` feature.
239    pub trait GeneralizedQuadsParser {
240        type Error: Error;
241
242        /// Parses the complete file and calls `on_quad` each time a new quad is read.
243        ///
244        /// May fails on errors caused by the parser itself or by the callback function `on_quad`.
245        fn parse_all<E: From<Self::Error>>(
246            &mut self,
247            on_quad: &mut impl FnMut(GeneralizedQuad<'_>) -> Result<(), E>,
248        ) -> Result<(), E> {
249            while !self.is_end() {
250                self.parse_step(on_quad)?
251            }
252            Ok(())
253        }
254
255        /// Parses a small chunk of the file and calls `on_quad` each time a new quad is read.
256        /// (A "small chunk" could be a line for an N-Quads parser.)
257        ///
258        /// This method should be called as long as [`is_end`](GeneralizedQuadsParser::is_end) returns false.
259        ///
260        /// May fails on errors caused by the parser itself or by the callback function `on_quad`.
261        fn parse_step<E: From<Self::Error>>(
262            &mut self,
263            on_quad: &mut impl FnMut(GeneralizedQuad<'_>) -> Result<(), E>,
264        ) -> Result<(), E>;
265
266        /// Returns `true` if the file has been completely consumed by the parser.
267        fn is_end(&self) -> bool;
268
269        /// Converts the parser into a `Result<T, E>` iterator.
270        ///
271        /// `convert_quad` is a function converting Rio [`GeneralizedQuad`]s to `T`.
272        fn into_iter<T, E, F>(
273            self,
274            convert_quad: F,
275        ) -> GeneralizedQuadsParserIterator<T, E, F, Self>
276        where
277            E: From<Self::Error>,
278            F: FnMut(GeneralizedQuad<'_>) -> Result<T, E>,
279            Self: Sized,
280        {
281            GeneralizedQuadsParserIterator {
282                parser: self,
283                buffer: Vec::default(),
284                convert_quad,
285            }
286        }
287    }
288
289    /// Created with the method [`into_iter`](GeneralizedQuadsParser::into_iter()).
290    ///
291    /// Using it requires to enable the `generalized` feature.
292    pub struct GeneralizedQuadsParserIterator<
293        T,
294        E: From<P::Error>,
295        F: FnMut(GeneralizedQuad<'_>) -> Result<T, E>,
296        P: GeneralizedQuadsParser,
297    > {
298        parser: P,
299        buffer: Vec<T>,
300        convert_quad: F,
301    }
302
303    impl<T, E, F, P> Iterator for GeneralizedQuadsParserIterator<T, E, F, P>
304    where
305        E: From<P::Error>,
306        F: FnMut(GeneralizedQuad<'_>) -> Result<T, E>,
307        P: GeneralizedQuadsParser + Sized,
308    {
309        type Item = Result<T, E>;
310
311        fn next(&mut self) -> Option<Result<T, E>> {
312            loop {
313                if let Some(r) = self.buffer.pop() {
314                    return Some(Ok(r));
315                }
316                if self.parser.is_end() {
317                    return None;
318                }
319
320                let buffer = &mut self.buffer;
321                let convert_quad = &mut self.convert_quad;
322                if let Err(e) = self
323                    .parser
324                    .parse_step(&mut |q| convert_quad(q).map(|q| buffer.push(q)))
325                {
326                    return Some(Err(e));
327                }
328            }
329        }
330    }
331}