use super::context::{JsonLdLoadDocumentOptions, JsonLdRemoteDocument, JsonLdTermDefinition};
use super::error::{JsonLdParseError, JsonLdSyntaxError};
use super::expansion::{JsonLdEvent, JsonLdExpansionConverter};
use super::to_rdf_converter::JsonLdToRdfConverter;
use crate::model::*;
#[cfg(feature = "async")]
use json_event_parser::TokioAsyncReaderJsonParser;
use json_event_parser::{JsonEvent, ReaderJsonParser, SliceJsonParser};
use oxiri::Iri;
use std::error::Error;
use std::io::Read;
use std::panic::{RefUnwindSafe, UnwindSafe};
#[cfg(feature = "async")]
use tokio::io::AsyncRead;
#[must_use]
pub struct ReaderJsonLdParser<R: Read> {
pub(super) results: Vec<Quad>,
pub(super) errors: Vec<JsonLdSyntaxError>,
pub(super) inner: InternalJsonLdParser,
pub(super) json_parser: ReaderJsonParser<R>,
}
impl<R: Read> Iterator for ReaderJsonLdParser<R> {
type Item = Result<Quad, JsonLdParseError>;
fn next(&mut self) -> Option<Self::Item> {
loop {
if let Some(error) = self.errors.pop() {
return Some(Err(error.into()));
} else if let Some(quad) = self.results.pop() {
return Some(Ok(quad));
} else if self.inner.is_end() {
return None;
}
let step = self.parse_step();
if let Err(e) = step {
return Some(Err(e));
}
self.results.reverse();
self.errors.reverse();
}
}
}
impl<R: Read> ReaderJsonLdParser<R> {
pub fn with_load_document_callback(
mut self,
callback: impl Fn(
&str,
&JsonLdLoadDocumentOptions,
) -> Result<JsonLdRemoteDocument, Box<dyn Error + Send + Sync>>
+ Send
+ Sync
+ UnwindSafe
+ RefUnwindSafe
+ 'static,
) -> Self {
self.inner.expansion = self.inner.expansion.with_load_document_callback(callback);
self
}
pub fn prefixes(&self) -> JsonLdPrefixesIter<'_> {
self.inner.prefixes()
}
pub fn base_iri(&self) -> Option<&str> {
self.inner.base_iri()
}
fn parse_step(&mut self) -> Result<(), JsonLdParseError> {
let event = match self.json_parser.parse_next() {
Ok(event) => event,
Err(e) => {
self.inner.json_error = true;
return Err(e.into());
}
};
self.inner
.parse_event(event, &mut self.results, &mut self.errors);
Ok(())
}
}
#[cfg(feature = "async")]
#[must_use]
pub struct TokioAsyncReaderJsonLdParser<R: AsyncRead + Unpin> {
pub(super) results: Vec<Quad>,
pub(super) errors: Vec<JsonLdSyntaxError>,
pub(super) inner: InternalJsonLdParser,
pub(super) json_parser: TokioAsyncReaderJsonParser<R>,
}
#[cfg(feature = "async")]
impl<R: AsyncRead + Unpin> TokioAsyncReaderJsonLdParser<R> {
pub async fn next(&mut self) -> Option<Result<Quad, JsonLdParseError>> {
loop {
if let Some(error) = self.errors.pop() {
return Some(Err(error.into()));
} else if let Some(quad) = self.results.pop() {
return Some(Ok(quad));
} else if self.inner.is_end() {
return None;
}
if let Err(e) = self.parse_step().await {
return Some(Err(e));
}
self.results.reverse();
self.errors.reverse();
}
}
pub fn prefixes(&self) -> JsonLdPrefixesIter<'_> {
self.inner.prefixes()
}
pub fn base_iri(&self) -> Option<&str> {
self.inner.base_iri()
}
async fn parse_step(&mut self) -> Result<(), JsonLdParseError> {
let event = match self.json_parser.parse_next().await {
Ok(e) => e,
Err(err) => {
self.inner.json_error = true;
return Err(err.into());
}
};
self.inner
.parse_event(event, &mut self.results, &mut self.errors);
Ok(())
}
}
#[must_use]
pub struct SliceJsonLdParser<'a> {
pub(super) results: Vec<Quad>,
pub(super) errors: Vec<JsonLdSyntaxError>,
pub(super) inner: InternalJsonLdParser,
pub(super) json_parser: SliceJsonParser<'a>,
}
impl Iterator for SliceJsonLdParser<'_> {
type Item = Result<Quad, JsonLdSyntaxError>;
fn next(&mut self) -> Option<Self::Item> {
loop {
if let Some(error) = self.errors.pop() {
return Some(Err(error));
} else if let Some(quad) = self.results.pop() {
return Some(Ok(quad));
} else if self.inner.is_end() {
return None;
}
if let Err(e) = self.parse_step() {
return Some(Err(e));
}
self.results.reverse();
self.errors.reverse();
}
}
}
impl SliceJsonLdParser<'_> {
pub fn with_load_document_callback(
mut self,
callback: impl Fn(
&str,
&JsonLdLoadDocumentOptions,
) -> Result<JsonLdRemoteDocument, Box<dyn Error + Send + Sync>>
+ Send
+ Sync
+ UnwindSafe
+ RefUnwindSafe
+ 'static,
) -> Self {
self.inner.expansion = self.inner.expansion.with_load_document_callback(callback);
self
}
pub fn prefixes(&self) -> JsonLdPrefixesIter<'_> {
self.inner.prefixes()
}
pub fn base_iri(&self) -> Option<&str> {
self.inner.base_iri()
}
fn parse_step(&mut self) -> Result<(), JsonLdSyntaxError> {
let event = match self.json_parser.parse_next() {
Ok(event) => event,
Err(e) => {
self.inner.json_error = true;
return Err(e.into());
}
};
self.inner
.parse_event(event, &mut self.results, &mut self.errors);
Ok(())
}
}
pub struct JsonLdPrefixesIter<'a> {
pub(super) term_definitions: std::collections::hash_map::Iter<'a, String, JsonLdTermDefinition>,
pub(super) lenient: bool,
}
impl<'a> Iterator for JsonLdPrefixesIter<'a> {
type Item = (&'a str, &'a str);
#[inline]
fn next(&mut self) -> Option<Self::Item> {
loop {
let (prefix, term_definition) = self.term_definitions.next()?;
if term_definition.prefix_flag {
if let Some(Some(mapping)) = &term_definition.iri_mapping {
if self.lenient || Iri::parse(mapping.as_str()).is_ok() {
return Some((prefix, mapping));
}
}
}
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(0, self.term_definitions.size_hint().1)
}
}
pub(super) struct InternalJsonLdParser {
pub(super) expansion: JsonLdExpansionConverter,
pub(super) expended_events: Vec<JsonLdEvent>,
pub(super) to_rdf: JsonLdToRdfConverter,
pub(super) json_error: bool,
}
impl InternalJsonLdParser {
pub(super) fn parse_event(
&mut self,
event: JsonEvent<'_>,
results: &mut Vec<Quad>,
errors: &mut Vec<JsonLdSyntaxError>,
) {
self.expansion
.convert_event(event, &mut self.expended_events, errors);
for event in self.expended_events.drain(..) {
self.to_rdf.convert_event(event, results);
}
}
pub(super) fn is_end(&self) -> bool {
self.json_error || self.expansion.is_end()
}
pub(super) fn base_iri(&self) -> Option<&str> {
Some(self.expansion.context().base_iri.as_ref()?.as_str())
}
pub(super) fn prefixes(&self) -> JsonLdPrefixesIter<'_> {
JsonLdPrefixesIter {
term_definitions: self.expansion.context().term_definitions.iter(),
lenient: self.to_rdf.lenient,
}
}
}