Skip to main content

sparesults/
parser.rs

1#![allow(clippy::large_enum_variant)]
2
3use crate::csv::{
4    ReaderTsvQueryResultsParserOutput, ReaderTsvSolutionsParser, SliceTsvQueryResultsParserOutput,
5    SliceTsvSolutionsParser,
6};
7#[cfg(feature = "async-tokio")]
8use crate::csv::{TokioAsyncReaderTsvQueryResultsParserOutput, TokioAsyncReaderTsvSolutionsParser};
9use crate::error::{QueryResultsParseError, QueryResultsSyntaxError};
10use crate::format::QueryResultsFormat;
11use crate::json::{
12    ReaderJsonQueryResultsParserOutput, ReaderJsonSolutionsParser,
13    SliceJsonQueryResultsParserOutput, SliceJsonSolutionsParser,
14};
15#[cfg(feature = "async-tokio")]
16use crate::json::{
17    TokioAsyncReaderJsonQueryResultsParserOutput, TokioAsyncReaderJsonSolutionsParser,
18};
19use crate::solution::QuerySolution;
20use crate::xml::{
21    ReaderXmlQueryResultsParserOutput, ReaderXmlSolutionsParser, SliceXmlQueryResultsParserOutput,
22    SliceXmlSolutionsParser,
23};
24#[cfg(feature = "async-tokio")]
25use crate::xml::{TokioAsyncReaderXmlQueryResultsParserOutput, TokioAsyncReaderXmlSolutionsParser};
26use oxrdf::Variable;
27use std::io::Read;
28use std::sync::Arc;
29#[cfg(feature = "async-tokio")]
30use tokio::io::AsyncRead;
31
32/// Parsers for [SPARQL query](https://www.w3.org/TR/sparql11-query/) results serialization formats.
33///
34/// It currently supports the following formats:
35/// * [SPARQL Query Results XML Format](https://www.w3.org/TR/rdf-sparql-XMLres/) ([`QueryResultsFormat::Xml`](QueryResultsFormat::Xml)).
36/// * [SPARQL Query Results JSON Format](https://www.w3.org/TR/sparql11-results-json/) ([`QueryResultsFormat::Json`](QueryResultsFormat::Json)).
37/// * [SPARQL Query Results TSV Format](https://www.w3.org/TR/sparql11-results-csv-tsv/) ([`QueryResultsFormat::Tsv`](QueryResultsFormat::Tsv)).
38///
39/// Example in JSON (the API is the same for XML and TSV):
40/// ```
41/// use sparesults::{QueryResultsFormat, QueryResultsParser, ReaderQueryResultsParserOutput};
42/// use oxrdf::{Literal, Variable};
43///
44/// let json_parser = QueryResultsParser::from_format(QueryResultsFormat::Json);
45/// // boolean
46/// if let ReaderQueryResultsParserOutput::Boolean(v) = json_parser.clone().for_reader(br#"{"boolean":true}"#.as_slice())? {
47///     assert_eq!(v, true);
48/// }
49/// // solutions
50/// if let ReaderQueryResultsParserOutput::Solutions(solutions) = json_parser.for_reader(br#"{"head":{"vars":["foo","bar"]},"results":{"bindings":[{"foo":{"type":"literal","value":"test"}}]}}"#.as_slice())? {
51///     assert_eq!(solutions.variables(), &[Variable::new("foo")?, Variable::new("bar")?]);
52///     for solution in solutions {
53///         assert_eq!(solution?.iter().collect::<Vec<_>>(), vec![(&Variable::new("foo")?, &Literal::from("test").into())]);
54///     }
55/// }
56/// # Result::<_, Box<dyn std::error::Error>>::Ok(())
57/// ```
58#[must_use]
59#[derive(Clone)]
60pub struct QueryResultsParser {
61    format: QueryResultsFormat,
62}
63
64impl QueryResultsParser {
65    /// Builds a parser for the given format.
66    #[inline]
67    pub fn from_format(format: QueryResultsFormat) -> Self {
68        Self { format }
69    }
70
71    /// Reads a result file from a [`Read`] implementation.
72    ///
73    /// Reads are automatically buffered.
74    ///
75    /// Example in XML (the API is the same for JSON and TSV):
76    /// ```
77    /// use sparesults::{QueryResultsFormat, QueryResultsParser, ReaderQueryResultsParserOutput};
78    /// use oxrdf::{Literal, Variable};
79    ///
80    /// let xml_parser = QueryResultsParser::from_format(QueryResultsFormat::Xml);
81    ///
82    /// // boolean
83    /// if let ReaderQueryResultsParserOutput::Boolean(v) = xml_parser.clone().for_reader(br#"<sparql xmlns="http://www.w3.org/2005/sparql-results#"><head/><boolean>true</boolean></sparql>"#.as_slice())? {
84    ///     assert_eq!(v, true);
85    /// }
86    ///
87    /// // solutions
88    /// if let ReaderQueryResultsParserOutput::Solutions(solutions) = xml_parser.for_reader(br#"<sparql xmlns="http://www.w3.org/2005/sparql-results#"><head><variable name="foo"/><variable name="bar"/></head><results><result><binding name="foo"><literal>test</literal></binding></result></results></sparql>"#.as_slice())? {
89    ///     assert_eq!(solutions.variables(), &[Variable::new("foo")?, Variable::new("bar")?]);
90    ///     for solution in solutions {
91    ///         assert_eq!(solution?.iter().collect::<Vec<_>>(), vec![(&Variable::new("foo")?, &Literal::from("test").into())]);
92    ///     }
93    /// }
94    /// # Result::<_, Box<dyn std::error::Error>>::Ok(())
95    /// ```
96    pub fn for_reader<R: Read>(
97        self,
98        reader: R,
99    ) -> Result<ReaderQueryResultsParserOutput<R>, QueryResultsParseError> {
100        Ok(match self.format {
101            QueryResultsFormat::Xml => match ReaderXmlQueryResultsParserOutput::read(reader)? {
102                ReaderXmlQueryResultsParserOutput::Boolean(r) => ReaderQueryResultsParserOutput::Boolean(r),
103                ReaderXmlQueryResultsParserOutput::Solutions {
104                    solutions,
105                    variables,
106                } => ReaderQueryResultsParserOutput::Solutions(ReaderSolutionsParser {
107                    variables: variables.into(),
108                    solutions: ReaderSolutionsParserKind::Xml(solutions),
109                }),
110            },
111            QueryResultsFormat::Json => match ReaderJsonQueryResultsParserOutput::read(reader)? {
112                ReaderJsonQueryResultsParserOutput::Boolean(r) => ReaderQueryResultsParserOutput::Boolean(r),
113                ReaderJsonQueryResultsParserOutput::Solutions {
114                    solutions,
115                    variables,
116                } => ReaderQueryResultsParserOutput::Solutions(ReaderSolutionsParser {
117                    variables: variables.into(),
118                    solutions: ReaderSolutionsParserKind::Json(solutions),
119                }),
120            },
121            QueryResultsFormat::Csv => return Err(QueryResultsSyntaxError::msg("CSV SPARQL results syntax is lossy and can't be parsed to a proper RDF representation").into()),
122            QueryResultsFormat::Tsv => match ReaderTsvQueryResultsParserOutput::read(reader)? {
123                ReaderTsvQueryResultsParserOutput::Boolean(r) => ReaderQueryResultsParserOutput::Boolean(r),
124                ReaderTsvQueryResultsParserOutput::Solutions {
125                    solutions,
126                    variables,
127                } => ReaderQueryResultsParserOutput::Solutions(ReaderSolutionsParser {
128                    variables: variables.into(),
129                    solutions: ReaderSolutionsParserKind::Tsv(solutions),
130                }),
131            },
132        })
133    }
134
135    /// Reads a result file from a Tokio [`AsyncRead`] implementation.
136    ///
137    /// Reads are automatically buffered.
138    ///
139    /// Example in XML (the API is the same for JSON and TSV):
140    /// ```
141    /// # #[tokio::main(flavor = "current_thread")]
142    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
143    /// use sparesults::{QueryResultsFormat, QueryResultsParser, TokioAsyncReaderQueryResultsParserOutput};
144    /// use oxrdf::{Literal, Variable};
145    ///
146    /// let xml_parser = QueryResultsParser::from_format(QueryResultsFormat::Xml);
147    ///
148    /// // boolean
149    /// if let TokioAsyncReaderQueryResultsParserOutput::Boolean(v) = xml_parser.clone().for_tokio_async_reader(br#"<sparql xmlns="http://www.w3.org/2005/sparql-results#"><head/><boolean>true</boolean></sparql>"#.as_slice()).await? {
150    ///     assert_eq!(v, true);
151    /// }
152    ///
153    /// // solutions
154    /// if let TokioAsyncReaderQueryResultsParserOutput::Solutions(mut solutions) = xml_parser.for_tokio_async_reader(br#"<sparql xmlns="http://www.w3.org/2005/sparql-results#"><head><variable name="foo"/><variable name="bar"/></head><results><result><binding name="foo"><literal>test</literal></binding></result></results></sparql>"#.as_slice()).await? {
155    ///     assert_eq!(solutions.variables(), &[Variable::new("foo")?, Variable::new("bar")?]);
156    ///     while let Some(solution) = solutions.next().await {
157    ///         assert_eq!(solution?.iter().collect::<Vec<_>>(), vec![(&Variable::new("foo")?, &Literal::from("test").into())]);
158    ///     }
159    /// }
160    /// # Ok(())
161    /// # }
162    /// ```
163    #[cfg(feature = "async-tokio")]
164    pub async fn for_tokio_async_reader<R: AsyncRead + Unpin>(
165        self,
166        reader: R,
167    ) -> Result<TokioAsyncReaderQueryResultsParserOutput<R>, QueryResultsParseError> {
168        Ok(match self.format {
169            QueryResultsFormat::Xml => match TokioAsyncReaderXmlQueryResultsParserOutput::read(reader).await? {
170                TokioAsyncReaderXmlQueryResultsParserOutput::Boolean(r) => TokioAsyncReaderQueryResultsParserOutput::Boolean(r),
171                TokioAsyncReaderXmlQueryResultsParserOutput::Solutions {
172                    solutions,
173                    variables,
174                } => TokioAsyncReaderQueryResultsParserOutput::Solutions(TokioAsyncReaderSolutionsParser {
175                    variables: variables.into(),
176                    solutions: TokioAsyncReaderSolutionsParserKind::Xml(solutions),
177                }),
178            },
179            QueryResultsFormat::Json => match TokioAsyncReaderJsonQueryResultsParserOutput::read(reader).await? {
180                TokioAsyncReaderJsonQueryResultsParserOutput::Boolean(r) => TokioAsyncReaderQueryResultsParserOutput::Boolean(r),
181                TokioAsyncReaderJsonQueryResultsParserOutput::Solutions {
182                    solutions,
183                    variables,
184                } => TokioAsyncReaderQueryResultsParserOutput::Solutions(TokioAsyncReaderSolutionsParser {
185                    variables: variables.into(),
186                    solutions: TokioAsyncReaderSolutionsParserKind::Json(solutions),
187                }),
188            },
189            QueryResultsFormat::Csv => return Err(QueryResultsSyntaxError::msg("CSV SPARQL results syntax is lossy and can't be parsed to a proper RDF representation").into()),
190            QueryResultsFormat::Tsv => match TokioAsyncReaderTsvQueryResultsParserOutput::read(reader).await? {
191                TokioAsyncReaderTsvQueryResultsParserOutput::Boolean(r) => TokioAsyncReaderQueryResultsParserOutput::Boolean(r),
192                TokioAsyncReaderTsvQueryResultsParserOutput::Solutions {
193                    solutions,
194                    variables,
195                } => TokioAsyncReaderQueryResultsParserOutput::Solutions(TokioAsyncReaderSolutionsParser {
196                    variables: variables.into(),
197                    solutions: TokioAsyncReaderSolutionsParserKind::Tsv(solutions),
198                }),
199            },
200        })
201    }
202
203    /// Reads a result file from a [`Read`] implementation.
204    ///
205    /// Reads are automatically buffered.
206    ///
207    /// Example in XML (the API is the same for JSON and TSV):
208    /// ```
209    /// use sparesults::{QueryResultsFormat, QueryResultsParser, SliceQueryResultsParserOutput};
210    /// use oxrdf::{Literal, Variable};
211    ///
212    /// let xml_parser = QueryResultsParser::from_format(QueryResultsFormat::Xml);
213    ///
214    /// // boolean
215    /// if let SliceQueryResultsParserOutput::Boolean(v) = xml_parser.clone().for_slice(r#"<sparql xmlns="http://www.w3.org/2005/sparql-results#"><head/><boolean>true</boolean></sparql>"#)? {
216    ///     assert_eq!(v, true);
217    /// }
218    ///
219    /// // solutions
220    /// if let SliceQueryResultsParserOutput::Solutions(solutions) = xml_parser.for_slice(r#"<sparql xmlns="http://www.w3.org/2005/sparql-results#"><head><variable name="foo"/><variable name="bar"/></head><results><result><binding name="foo"><literal>test</literal></binding></result></results></sparql>"#)? {
221    ///     assert_eq!(solutions.variables(), &[Variable::new("foo")?, Variable::new("bar")?]);
222    ///     for solution in solutions {
223    ///         assert_eq!(solution?.iter().collect::<Vec<_>>(), vec![(&Variable::new("foo")?, &Literal::from("test").into())]);
224    ///     }
225    /// }
226    /// # Result::<_, Box<dyn std::error::Error>>::Ok(())
227    /// ```
228    pub fn for_slice(
229        self,
230        slice: &(impl AsRef<[u8]> + ?Sized),
231    ) -> Result<SliceQueryResultsParserOutput<'_>, QueryResultsSyntaxError> {
232        Ok(match self.format {
233            QueryResultsFormat::Xml => {
234                match SliceXmlQueryResultsParserOutput::read(slice.as_ref())? {
235                    SliceXmlQueryResultsParserOutput::Boolean(r) => {
236                        SliceQueryResultsParserOutput::Boolean(r)
237                    }
238                    SliceXmlQueryResultsParserOutput::Solutions {
239                        solutions,
240                        variables,
241                    } => SliceQueryResultsParserOutput::Solutions(SliceSolutionsParser {
242                        variables: variables.into(),
243                        solutions: SliceSolutionsParserKind::Xml(solutions),
244                    }),
245                }
246            }
247            QueryResultsFormat::Json => {
248                match SliceJsonQueryResultsParserOutput::read(slice.as_ref())? {
249                    SliceJsonQueryResultsParserOutput::Boolean(r) => {
250                        SliceQueryResultsParserOutput::Boolean(r)
251                    }
252                    SliceJsonQueryResultsParserOutput::Solutions {
253                        solutions,
254                        variables,
255                    } => SliceQueryResultsParserOutput::Solutions(SliceSolutionsParser {
256                        variables: variables.into(),
257                        solutions: SliceSolutionsParserKind::Json(solutions),
258                    }),
259                }
260            }
261            QueryResultsFormat::Csv => {
262                return Err(QueryResultsSyntaxError::msg(
263                    "CSV SPARQL results syntax is lossy and can't be parsed to a proper RDF representation",
264                ));
265            }
266            QueryResultsFormat::Tsv => {
267                match SliceTsvQueryResultsParserOutput::read(slice.as_ref())? {
268                    SliceTsvQueryResultsParserOutput::Boolean(r) => {
269                        SliceQueryResultsParserOutput::Boolean(r)
270                    }
271                    SliceTsvQueryResultsParserOutput::Solutions {
272                        solutions,
273                        variables,
274                    } => SliceQueryResultsParserOutput::Solutions(SliceSolutionsParser {
275                        variables: variables.into(),
276                        solutions: SliceSolutionsParserKind::Tsv(solutions),
277                    }),
278                }
279            }
280        })
281    }
282}
283
284impl From<QueryResultsFormat> for QueryResultsParser {
285    fn from(format: QueryResultsFormat) -> Self {
286        Self::from_format(format)
287    }
288}
289
290/// The reader for a given read of a results file.
291///
292/// It is either a read boolean ([`bool`]) or a streaming reader of a set of solutions ([`ReaderSolutionsParser`]).
293///
294/// Example in TSV (the API is the same for JSON and XML):
295/// ```
296/// use oxrdf::{Literal, Variable};
297/// use sparesults::{QueryResultsFormat, QueryResultsParser, ReaderQueryResultsParserOutput};
298///
299/// let tsv_parser = QueryResultsParser::from_format(QueryResultsFormat::Tsv);
300///
301/// // boolean
302/// if let ReaderQueryResultsParserOutput::Boolean(v) =
303///     tsv_parser.clone().for_reader("true".as_bytes())?
304/// {
305///     assert_eq!(v, true);
306/// }
307///
308/// // solutions
309/// if let ReaderQueryResultsParserOutput::Solutions(solutions) =
310///     tsv_parser.for_reader("?foo\t?bar\n\"test\"\t".as_bytes())?
311/// {
312///     assert_eq!(
313///         solutions.variables(),
314///         &[Variable::new("foo")?, Variable::new("bar")?]
315///     );
316///     for solution in solutions {
317///         assert_eq!(
318///             solution?.iter().collect::<Vec<_>>(),
319///             vec![(&Variable::new("foo")?, &Literal::from("test").into())]
320///         );
321///     }
322/// }
323/// # Result::<_, Box<dyn std::error::Error>>::Ok(())
324/// ```
325pub enum ReaderQueryResultsParserOutput<R: Read> {
326    Solutions(ReaderSolutionsParser<R>),
327    Boolean(bool),
328}
329
330/// A streaming parser of a set of [`QuerySolution`] solutions.
331///
332/// It implements the [`Iterator`] API to iterate over the solutions.
333///
334/// Example in JSON (the API is the same for XML and TSV):
335/// ```
336/// use sparesults::{QueryResultsFormat, QueryResultsParser, ReaderQueryResultsParserOutput};
337/// use oxrdf::{Literal, Variable};
338///
339/// let json_parser = QueryResultsParser::from_format(QueryResultsFormat::Json);
340/// if let ReaderQueryResultsParserOutput::Solutions(solutions) = json_parser.for_reader(br#"{"head":{"vars":["foo","bar"]},"results":{"bindings":[{"foo":{"type":"literal","value":"test"}}]}}"#.as_slice())? {
341///     assert_eq!(solutions.variables(), &[Variable::new("foo")?, Variable::new("bar")?]);
342///     for solution in solutions {
343///         assert_eq!(solution?.iter().collect::<Vec<_>>(), vec![(&Variable::new("foo")?, &Literal::from("test").into())]);
344///     }
345/// }
346/// # Result::<_, Box<dyn std::error::Error>>::Ok(())
347/// ```
348pub struct ReaderSolutionsParser<R: Read> {
349    variables: Arc<[Variable]>,
350    solutions: ReaderSolutionsParserKind<R>,
351}
352
353enum ReaderSolutionsParserKind<R: Read> {
354    Xml(ReaderXmlSolutionsParser<R>),
355    Json(ReaderJsonSolutionsParser<R>),
356    Tsv(ReaderTsvSolutionsParser<R>),
357}
358
359impl<R: Read> ReaderSolutionsParser<R> {
360    /// Ordered list of the declared variables at the beginning of the results.
361    ///
362    /// Example in TSV (the API is the same for JSON and XML):
363    /// ```
364    /// use oxrdf::Variable;
365    /// use sparesults::{QueryResultsFormat, QueryResultsParser, ReaderQueryResultsParserOutput};
366    ///
367    /// let tsv_parser = QueryResultsParser::from_format(QueryResultsFormat::Tsv);
368    /// if let ReaderQueryResultsParserOutput::Solutions(solutions) =
369    ///     tsv_parser.for_reader(b"?foo\t?bar\n\"ex1\"\t\"ex2\"".as_slice())?
370    /// {
371    ///     assert_eq!(
372    ///         solutions.variables(),
373    ///         &[Variable::new("foo")?, Variable::new("bar")?]
374    ///     );
375    /// }
376    /// # Result::<_, Box<dyn std::error::Error>>::Ok(())
377    /// ```
378    #[inline]
379    pub fn variables(&self) -> &[Variable] {
380        &self.variables
381    }
382}
383
384impl<R: Read> Iterator for ReaderSolutionsParser<R> {
385    type Item = Result<QuerySolution, QueryResultsParseError>;
386
387    fn next(&mut self) -> Option<Self::Item> {
388        Some(
389            match &mut self.solutions {
390                ReaderSolutionsParserKind::Xml(reader) => reader.parse_next(),
391                ReaderSolutionsParserKind::Json(reader) => reader.parse_next(),
392                ReaderSolutionsParserKind::Tsv(reader) => reader.parse_next(),
393            }
394            .transpose()?
395            .map(|values| (Arc::clone(&self.variables), values).into()),
396        )
397    }
398}
399
400/// The reader for a given read of a results file.
401///
402/// It is either a read boolean ([`bool`]) or a streaming reader of a set of solutions ([`ReaderSolutionsParser`]).
403///
404/// Example in TSV (the API is the same for JSON and XML):
405/// ```
406/// # #[tokio::main(flavor = "current_thread")]
407/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
408/// use oxrdf::{Literal, Variable};
409/// use sparesults::{
410///     QueryResultsFormat, QueryResultsParser, TokioAsyncReaderQueryResultsParserOutput,
411/// };
412///
413/// let tsv_parser = QueryResultsParser::from_format(QueryResultsFormat::Tsv);
414///
415/// // boolean
416/// if let TokioAsyncReaderQueryResultsParserOutput::Boolean(v) = tsv_parser
417///     .clone()
418///     .for_tokio_async_reader(b"true".as_slice())
419///     .await?
420/// {
421///     assert_eq!(v, true);
422/// }
423///
424/// // solutions
425/// if let TokioAsyncReaderQueryResultsParserOutput::Solutions(mut solutions) = tsv_parser
426///     .for_tokio_async_reader(b"?foo\t?bar\n\"test\"\t".as_slice())
427///     .await?
428/// {
429///     assert_eq!(
430///         solutions.variables(),
431///         &[Variable::new("foo")?, Variable::new("bar")?]
432///     );
433///     while let Some(solution) = solutions.next().await {
434///         assert_eq!(
435///             solution?.iter().collect::<Vec<_>>(),
436///             vec![(&Variable::new("foo")?, &Literal::from("test").into())]
437///         );
438///     }
439/// }
440/// # Ok(())
441/// # }
442/// ```
443#[cfg(feature = "async-tokio")]
444pub enum TokioAsyncReaderQueryResultsParserOutput<R: AsyncRead + Unpin> {
445    Solutions(TokioAsyncReaderSolutionsParser<R>),
446    Boolean(bool),
447}
448
449/// A streaming parser of a set of [`QuerySolution`] solutions.
450///
451/// It implements the [`Iterator`] API to iterate over the solutions.
452///
453/// Example in JSON (the API is the same for XML and TSV):
454/// ```
455/// # #[tokio::main(flavor = "current_thread")]
456/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
457/// use sparesults::{QueryResultsFormat, QueryResultsParser, TokioAsyncReaderQueryResultsParserOutput};
458/// use oxrdf::{Literal, Variable};
459///
460/// let json_parser = QueryResultsParser::from_format(QueryResultsFormat::Json);
461/// if let TokioAsyncReaderQueryResultsParserOutput::Solutions(mut solutions) = json_parser.for_tokio_async_reader(br#"{"head":{"vars":["foo","bar"]},"results":{"bindings":[{"foo":{"type":"literal","value":"test"}}]}}"#.as_slice()).await? {
462///     assert_eq!(solutions.variables(), &[Variable::new("foo")?, Variable::new("bar")?]);
463///     while let Some(solution) = solutions.next().await {
464///         assert_eq!(solution?.iter().collect::<Vec<_>>(), vec![(&Variable::new("foo")?, &Literal::from("test").into())]);
465///     }
466/// }
467/// # Ok(())
468/// # }
469/// ```
470#[cfg(feature = "async-tokio")]
471pub struct TokioAsyncReaderSolutionsParser<R: AsyncRead + Unpin> {
472    variables: Arc<[Variable]>,
473    solutions: TokioAsyncReaderSolutionsParserKind<R>,
474}
475
476#[cfg(feature = "async-tokio")]
477enum TokioAsyncReaderSolutionsParserKind<R: AsyncRead + Unpin> {
478    Json(TokioAsyncReaderJsonSolutionsParser<R>),
479    Xml(TokioAsyncReaderXmlSolutionsParser<R>),
480    Tsv(TokioAsyncReaderTsvSolutionsParser<R>),
481}
482
483#[cfg(feature = "async-tokio")]
484impl<R: AsyncRead + Unpin> TokioAsyncReaderSolutionsParser<R> {
485    /// Ordered list of the declared variables at the beginning of the results.
486    ///
487    /// Example in TSV (the API is the same for JSON and XML):
488    /// ```
489    /// # #[tokio::main(flavor = "current_thread")]
490    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
491    /// use oxrdf::Variable;
492    /// use sparesults::{
493    ///     QueryResultsFormat, QueryResultsParser, TokioAsyncReaderQueryResultsParserOutput,
494    /// };
495    ///
496    /// let tsv_parser = QueryResultsParser::from_format(QueryResultsFormat::Tsv);
497    /// if let TokioAsyncReaderQueryResultsParserOutput::Solutions(solutions) = tsv_parser
498    ///     .for_tokio_async_reader(b"?foo\t?bar\n\"ex1\"\t\"ex2\"".as_slice())
499    ///     .await?
500    /// {
501    ///     assert_eq!(
502    ///         solutions.variables(),
503    ///         &[Variable::new("foo")?, Variable::new("bar")?]
504    ///     );
505    /// }
506    /// # Ok(())
507    /// # }
508    /// ```
509    #[inline]
510    pub fn variables(&self) -> &[Variable] {
511        &self.variables
512    }
513
514    /// Reads the next solution or returns `None` if the file is finished.
515    pub async fn next(&mut self) -> Option<Result<QuerySolution, QueryResultsParseError>> {
516        Some(
517            match &mut self.solutions {
518                TokioAsyncReaderSolutionsParserKind::Json(reader) => reader.parse_next().await,
519                TokioAsyncReaderSolutionsParserKind::Xml(reader) => reader.parse_next().await,
520                TokioAsyncReaderSolutionsParserKind::Tsv(reader) => reader.parse_next().await,
521            }
522            .transpose()?
523            .map(|values| (Arc::clone(&self.variables), values).into()),
524        )
525    }
526}
527
528/// The reader for a given read of a results file.
529///
530/// It is either a read boolean ([`bool`]) or a streaming reader of a set of solutions ([`SliceSolutionsParser`]).
531///
532/// Example in TSV (the API is the same for JSON and XML):
533/// ```
534/// use oxrdf::{Literal, Variable};
535/// use sparesults::{QueryResultsFormat, QueryResultsParser, ReaderQueryResultsParserOutput};
536///
537/// let tsv_parser = QueryResultsParser::from_format(QueryResultsFormat::Tsv);
538///
539/// // boolean
540/// if let ReaderQueryResultsParserOutput::Boolean(v) =
541///     tsv_parser.clone().for_reader(b"true".as_slice())?
542/// {
543///     assert_eq!(v, true);
544/// }
545///
546/// // solutions
547/// if let ReaderQueryResultsParserOutput::Solutions(solutions) =
548///     tsv_parser.for_reader(b"?foo\t?bar\n\"test\"\t".as_slice())?
549/// {
550///     assert_eq!(
551///         solutions.variables(),
552///         &[Variable::new("foo")?, Variable::new("bar")?]
553///     );
554///     for solution in solutions {
555///         assert_eq!(
556///             solution?.iter().collect::<Vec<_>>(),
557///             vec![(&Variable::new("foo")?, &Literal::from("test").into())]
558///         );
559///     }
560/// }
561/// # Result::<_, Box<dyn std::error::Error>>::Ok(())
562/// ```
563pub enum SliceQueryResultsParserOutput<'a> {
564    Solutions(SliceSolutionsParser<'a>),
565    Boolean(bool),
566}
567
568/// A streaming parser of a set of [`QuerySolution`] solutions.
569///
570/// It implements the [`Iterator`] API to iterate over the solutions.
571///
572/// Example in JSON (the API is the same for XML and TSV):
573/// ```
574/// use sparesults::{QueryResultsFormat, QueryResultsParser, SliceQueryResultsParserOutput};
575/// use oxrdf::{Literal, Variable};
576///
577/// let json_parser = QueryResultsParser::from_format(QueryResultsFormat::Json);
578/// if let SliceQueryResultsParserOutput::Solutions(solutions) = json_parser.for_slice(r#"{"head":{"vars":["foo","bar"]},"results":{"bindings":[{"foo":{"type":"literal","value":"test"}}]}}"#)? {
579///     assert_eq!(solutions.variables(), &[Variable::new("foo")?, Variable::new("bar")?]);
580///     for solution in solutions {
581///         assert_eq!(solution?.iter().collect::<Vec<_>>(), vec![(&Variable::new("foo")?, &Literal::from("test").into())]);
582///     }
583/// }
584/// # Result::<_, Box<dyn std::error::Error>>::Ok(())
585/// ```
586pub struct SliceSolutionsParser<'a> {
587    variables: Arc<[Variable]>,
588    solutions: SliceSolutionsParserKind<'a>,
589}
590
591enum SliceSolutionsParserKind<'a> {
592    Xml(SliceXmlSolutionsParser<'a>),
593    Json(SliceJsonSolutionsParser<'a>),
594    Tsv(SliceTsvSolutionsParser<'a>),
595}
596
597impl SliceSolutionsParser<'_> {
598    /// Ordered list of the declared variables at the beginning of the results.
599    ///
600    /// Example in TSV (the API is the same for JSON and XML):
601    /// ```
602    /// use oxrdf::Variable;
603    /// use sparesults::{QueryResultsFormat, QueryResultsParser, SliceQueryResultsParserOutput};
604    ///
605    /// let tsv_parser = QueryResultsParser::from_format(QueryResultsFormat::Tsv);
606    /// if let SliceQueryResultsParserOutput::Solutions(solutions) =
607    ///     tsv_parser.for_slice("?foo\t?bar\n\"ex1\"\t\"ex2\"")?
608    /// {
609    ///     assert_eq!(
610    ///         solutions.variables(),
611    ///         &[Variable::new("foo")?, Variable::new("bar")?]
612    ///     );
613    /// }
614    /// # Result::<_, Box<dyn std::error::Error>>::Ok(())
615    /// ```
616    #[inline]
617    pub fn variables(&self) -> &[Variable] {
618        &self.variables
619    }
620}
621
622impl Iterator for SliceSolutionsParser<'_> {
623    type Item = Result<QuerySolution, QueryResultsSyntaxError>;
624
625    fn next(&mut self) -> Option<Self::Item> {
626        Some(
627            match &mut self.solutions {
628                SliceSolutionsParserKind::Xml(reader) => reader.parse_next(),
629                SliceSolutionsParserKind::Json(reader) => reader.parse_next(),
630                SliceSolutionsParserKind::Tsv(reader) => reader.parse_next(),
631            }
632            .transpose()?
633            .map(|values| (Arc::clone(&self.variables), values).into()),
634        )
635    }
636}