From 376c6f1a8a280c4232b9cc8430b7e41a7998485d Mon Sep 17 00:00:00 2001 From: Pierre-Antoine Champin Date: Fri, 24 Nov 2023 19:09:41 +0100 Subject: [PATCH] make wasm-friendly --- Cargo.toml | 2 +- jsonld/Cargo.toml | 3 +- jsonld/src/loader.rs | 2 + jsonld/src/loader/chain_loader.rs | 2 +- jsonld/src/loader/closure_loader.rs | 2 +- jsonld/src/loader/file_url_loader.rs | 2 +- jsonld/src/loader/static_loader.rs | 2 +- jsonld/src/options.rs | 7 ++- jsonld/src/parser.rs | 71 ++++++++++++++++++---------- 9 files changed, 58 insertions(+), 35 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 870a1739..7fd02e55 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,7 +51,7 @@ rio_turtle = { version = "0.8", features = ["generalized"] } rio_xml = { version = "0.8" } test-case = "3.1.0" thiserror = "1.0.32" -tokio = { version="1.33.0", features = ["rt"] } +tokio = { version="1.33.0", features = ["rt", "sync"] } url = "2.4.1" [profile.release] diff --git a/jsonld/Cargo.toml b/jsonld/Cargo.toml index 8ebda680..925f24e3 100644 --- a/jsonld/Cargo.toml +++ b/jsonld/Cargo.toml @@ -20,9 +20,8 @@ file_url = ["dep:url"] http_client = ["json-ld/reqwest"] [dependencies] -futures-util.workspace = true iref = "2.2" -json-ld = "0.15.0" +json-ld = { version = "0.15.0", git = "https://github.com/pchampin/json-ld", branch="wasm-0.15.0" } json-syntax = "0.9" langtag = "0.3.4" locspan = "0.7.12" diff --git a/jsonld/src/loader.rs b/jsonld/src/loader.rs index 0efc2bf0..27b10bcb 100644 --- a/jsonld/src/loader.rs +++ b/jsonld/src/loader.rs @@ -11,6 +11,8 @@ use json_syntax::Value; use locspan::Location; use sophia_iri::Iri; +pub use json_ld::{BoxFuture, FutureExt}; + /// A dummy document loader, that does not load anything. pub type NoLoader = json_ld::NoLoader>, Location>>, Value>>>>; diff --git a/jsonld/src/loader/chain_loader.rs b/jsonld/src/loader/chain_loader.rs index fb51e120..00f1af98 100644 --- a/jsonld/src/loader/chain_loader.rs +++ b/jsonld/src/loader/chain_loader.rs @@ -1,7 +1,7 @@ use std::fmt::Debug; -use futures_util::future::{BoxFuture, FutureExt}; use json_ld::Loader; +use json_ld::{BoxFuture, FutureExt}; use json_syntax::Value; use locspan::Location; diff --git a/jsonld/src/loader/closure_loader.rs b/jsonld/src/loader/closure_loader.rs index 97565334..07affc85 100644 --- a/jsonld/src/loader/closure_loader.rs +++ b/jsonld/src/loader/closure_loader.rs @@ -1,5 +1,5 @@ use super::*; -use futures_util::future::{BoxFuture, FutureExt}; +use json_ld::{BoxFuture, FutureExt}; use json_ld::{Loader, RemoteDocument}; use json_syntax::Parse; use locspan::{Location, Meta}; diff --git a/jsonld/src/loader/file_url_loader.rs b/jsonld/src/loader/file_url_loader.rs index 7c66f591..c671d32d 100644 --- a/jsonld/src/loader/file_url_loader.rs +++ b/jsonld/src/loader/file_url_loader.rs @@ -1,5 +1,5 @@ use super::*; -use futures_util::future::{BoxFuture, FutureExt}; +use json_ld::{BoxFuture, FutureExt}; use json_ld::{Loader, RemoteDocument}; use json_syntax::Parse; use locspan::{Location, Meta}; diff --git a/jsonld/src/loader/static_loader.rs b/jsonld/src/loader/static_loader.rs index 98dfbe84..2278e63f 100644 --- a/jsonld/src/loader/static_loader.rs +++ b/jsonld/src/loader/static_loader.rs @@ -1,6 +1,6 @@ use std::{collections::HashMap, fmt::Debug}; -use futures_util::future::{BoxFuture, FutureExt}; +use json_ld::{BoxFuture, FutureExt}; use json_ld::{Loader, RemoteDocument}; use json_syntax::Value; use locspan::{Location, Meta}; diff --git a/jsonld/src/options.rs b/jsonld/src/options.rs index ce9bbc05..eeea73a5 100644 --- a/jsonld/src/options.rs +++ b/jsonld/src/options.rs @@ -1,7 +1,5 @@ //! Defines types for configuring JSON-LD processing. -use std::sync::{LockResult, Mutex, MutexGuard}; - use json_ld::expansion::Policy; pub use json_ld::rdf::RdfDirection; use json_ld::syntax::context::Value; @@ -10,6 +8,7 @@ pub use json_ld::ProcessingMode; use locspan::Location; use locspan::Span; use sophia_iri::Iri; +use tokio::sync::{Mutex, MutexGuard}; use crate::loader::NoLoader; use crate::vocabulary::ArcIri; @@ -68,8 +67,8 @@ impl JsonLdOptions { /// The [`documentLoader`] is used to retrieve remote documents and contexts. /// /// [`documentLoader`]: https://www.w3.org/TR/json-ld11-api/#dom-jsonldoptions-documentloader - pub fn document_loader(&self) -> LockResult> { - self.loader.lock() + pub async fn document_loader(&self) -> MutexGuard { + self.loader.lock().await } /// [`expandContext`] is a context that is used to initialize the active context when expanding a document. diff --git a/jsonld/src/parser.rs b/jsonld/src/parser.rs index 09d17bba..344ac705 100644 --- a/jsonld/src/parser.rs +++ b/jsonld/src/parser.rs @@ -30,6 +30,14 @@ mod test; /// /// * the generic parameter `L` is the type of the [document loader](`json_ld::Loader`) /// (determined by the `options` parameters) +/// +/// ## WebAssembly +/// +/// In some situations, +/// the methods from the [`QuadParser`] trait panic when executed as WebAssembly +/// (this is not the case when using the [`NoLoader`], +/// but occurs when using the [`HttpLoader`](crate::loader::HttpLoader)). +/// Those panics can be avoided by using the [`JsonLdParser::async_parse_str`] method. pub struct JsonLdParser { options: JsonLdOptions, } @@ -61,7 +69,7 @@ impl JsonLdParser { } /// Parse (as RDF) a pre-parsed (as JSON) document - pub fn parse_json(&self, data: &RemoteDocument) -> JsonLdQuadSource + pub async fn parse_json(&self, data: &RemoteDocument) -> JsonLdQuadSource where L: Loader> + json_ld::ContextLoader> @@ -77,18 +85,14 @@ impl JsonLdParser { Span::default(), ); let mut generator = rdf_types::generator::Blank::new().with_metadata(gen_loc); - let mut g_loader = match self.options.document_loader() { - Ok(g) => g, - Err(err) => return JsonLdQuadSource::from_err(err), - }; + let mut g_loader = self.options.document_loader().await; let loader = g_loader.deref_mut(); let mut vocab = ArcVoc {}; let options = self.options.inner().clone(); - let rt = tokio::runtime::Builder::new_current_thread() - .enable_all() - .build() - .expect("Could not build tokio runtime"); - match rt.block_on(data.to_rdf_with_using(&mut vocab, &mut generator, loader, options)) { + match data + .to_rdf_with_using(&mut vocab, &mut generator, loader, options) + .await + { Err(ToRdfError::Expand(err)) => JsonLdQuadSource::from_err(err), Ok(mut to_rdf) => JsonLdQuadSource::Quads( to_rdf @@ -99,6 +103,34 @@ impl JsonLdParser { ), } } + + /// Parse (as RDF) a JSON-LD string, asynchronously + pub async fn async_parse_str<'t>(&self, txt: &'t str) -> JsonLdQuadSource + where + L: Loader> + + json_ld::ContextLoader> + + Send + + Sync, + L::Output: Into>>, + L::Error: Display + Send, + L::Context: Into>>, + L::ContextError: Display + Send, + { + let base = self + .options() + .base() + .unwrap_or(Iri::new_unchecked_const("x-string://")) + .map_unchecked(Arc::from); + let json_res = Value::parse_str(txt, |span| Location::new(base.clone(), span)); + let json = match json_res { + Ok(json) => json, + Err(err) => { + return JsonLdQuadSource::from_err(err); + } + }; + let doc = RemoteDocument::new(Some(base), None, json); + self.parse_json(&doc).await + } } impl QuadParser for JsonLdParser @@ -130,20 +162,11 @@ where where &'t str: sophia_api::parser::IntoParsable, { - let base = self - .options() - .base() - .unwrap_or(Iri::new_unchecked_const("x-string://")) - .map_unchecked(Arc::from); - let json_res = Value::parse_str(txt, |span| Location::new(base.clone(), span)); - let json = match json_res { - Ok(json) => json, - Err(err) => { - return JsonLdQuadSource::from_err(err); - } - }; - let doc = RemoteDocument::new(Some(base), None, json); - self.parse_json(&doc) + let rt = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .expect("Could not build tokio runtime"); + rt.block_on(self.async_parse_str(txt)) } }