mod definition;
pub mod inverse;
mod loader;
mod processing;
use crate::{
lang::{LenientLanguageTag, LenientLanguageTagBuf},
syntax::Term,
util::{AsJson, JsonFrom},
Direction, Error, Id, Loc, ProcessingMode, Warning,
};
use futures::{future::BoxFuture, FutureExt};
use generic_json::{JsonClone, JsonSendSync};
use iref::{Iri, IriBuf};
use std::collections::HashMap;
pub use definition::*;
pub use inverse::{InverseContext, Inversible};
pub use loader::*;
use processing::*;
pub trait JsonContext = JsonSendSync + JsonClone;
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct ProcessingOptions {
pub processing_mode: ProcessingMode,
pub override_protected: bool,
pub propagate: bool,
}
impl ProcessingOptions {
#[must_use]
pub fn with_override(&self) -> ProcessingOptions {
let mut opt = *self;
opt.override_protected = true;
opt
}
#[must_use]
pub fn with_no_override(&self) -> ProcessingOptions {
let mut opt = *self;
opt.override_protected = false;
opt
}
#[must_use]
pub fn without_propagation(&self) -> ProcessingOptions {
let mut opt = *self;
opt.propagate = false;
opt
}
}
impl Default for ProcessingOptions {
fn default() -> ProcessingOptions {
ProcessingOptions {
processing_mode: ProcessingMode::default(),
override_protected: false,
propagate: true,
}
}
}
pub trait Context<T: Id = IriBuf>: Clone {
type LocalContext: Local<T>;
fn new(base_iri: Option<Iri>) -> Self;
fn get(&self, term: &str) -> Option<&TermDefinition<T, Self>>;
fn get_opt(&self, term: Option<&str>) -> Option<&TermDefinition<T, Self>> {
if let Some(term) = term {
self.get(term)
} else {
None
}
}
#[inline]
fn contains(&self, term: &str) -> bool {
self.get(term).is_some()
}
fn original_base_url(&self) -> Option<Iri>;
fn base_iri(&self) -> Option<Iri>;
fn vocabulary(&self) -> Option<&Term<T>>;
fn default_language(&self) -> Option<LenientLanguageTag>;
fn default_base_direction(&self) -> Option<Direction>;
fn previous_context(&self) -> Option<&Self>;
fn definitions<'a>(
&'a self,
) -> Box<dyn 'a + Iterator<Item = (&'a String, &'a TermDefinition<T, Self>)>>;
}
pub trait ContextMut<T: Id = IriBuf>: Context<T> {
fn set(
&mut self,
term: &str,
definition: Option<TermDefinition<T, Self>>,
) -> Option<TermDefinition<T, Self>>;
fn set_base_iri(&mut self, iri: Option<Iri>);
fn set_vocabulary(&mut self, vocab: Option<Term<T>>);
fn set_default_language(&mut self, lang: Option<LenientLanguageTagBuf>);
fn set_default_base_direction(&mut self, dir: Option<Direction>);
fn set_previous_context(&mut self, previous: Self);
}
pub trait ContextMutProxy<T: Id = IriBuf> {
type Target: ContextMut<T>;
fn deref(&self) -> &Self::Target;
}
pub type ProcessingResult<'s, J, C> =
Result<Processed<'s, J, C>, Loc<Error, <J as generic_json::Json>::MetaData>>;
pub trait Local<T: Id = IriBuf>: JsonSendSync {
fn process_full<'a, 's: 'a, C: ContextMut<T> + Send + Sync, L: Loader + Send + Sync>(
&'s self,
active_context: &'a C,
stack: ProcessingStack,
loader: &'a mut L,
base_url: Option<Iri<'a>>,
options: ProcessingOptions,
) -> BoxFuture<'a, ProcessingResult<'s, Self, C>>
where
C::LocalContext: From<L::Output> + From<Self>,
L::Output: Into<Self>,
T: Send + Sync;
fn process_with<'a, 's: 'a, C: ContextMut<T> + Send + Sync, L: Loader + Send + Sync>(
&'s self,
active_context: &'a C,
loader: &'a mut L,
base_url: Option<Iri<'a>>,
options: ProcessingOptions,
) -> BoxFuture<'a, ProcessingResult<'s, Self, C>>
where
C::LocalContext: From<L::Output> + From<Self>,
L::Output: Into<Self>,
T: Send + Sync,
{
self.process_full(
active_context,
ProcessingStack::new(),
loader,
base_url,
options,
)
}
fn process<'a, 's: 'a, C: ContextMut<T> + Default + Send + Sync, L: Loader + Send + Sync>(
&'s self,
loader: &'a mut L,
base_url: Option<Iri<'a>>,
) -> BoxFuture<'a, ProcessingResult<'s, Self, C>>
where
C::LocalContext: From<L::Output> + From<Self>,
L::Output: Into<Self>,
T: Send + Sync,
{
async move {
let active_context = C::default();
self.process_full(
&active_context,
ProcessingStack::new(),
loader,
base_url,
ProcessingOptions::default(),
)
.await
}
.boxed()
}
}
#[derive(Clone)]
pub struct ProcessedOwned<L: generic_json::Json, C> {
local: L,
processed: C,
warnings: Vec<Loc<Warning, L::MetaData>>,
}
impl<L: generic_json::Json, C> ProcessedOwned<L, C> {
pub fn new(local: L, processed: C) -> ProcessedOwned<L, C> {
Self::with_warnings(local, processed, Vec::new())
}
pub fn with_warnings(local: L, processed: C, warnings: Vec<Loc<Warning, L::MetaData>>) -> Self {
ProcessedOwned {
local,
processed,
warnings,
}
}
pub fn warnings(&self) -> &[Loc<Warning, L::MetaData>] {
&self.warnings
}
pub fn into_inner(self) -> C {
self.processed
}
}
impl<T: Id, L: generic_json::Json, C: ContextMut<T>> ContextMutProxy<T> for ProcessedOwned<L, C> {
type Target = C;
fn deref(&self) -> &C {
&self.processed
}
}
impl<L: generic_json::Json, C> std::ops::Deref for ProcessedOwned<L, C> {
type Target = C;
fn deref(&self) -> &C {
&self.processed
}
}
impl<L: generic_json::Json, C> std::convert::AsRef<C> for ProcessedOwned<L, C> {
fn as_ref(&self) -> &C {
&self.processed
}
}
impl<J: JsonClone, K: JsonFrom<J>, L: generic_json::Json + AsJson<J, K>, C> AsJson<J, K>
for ProcessedOwned<L, C>
{
fn as_json_with(&self, meta: impl Clone + Fn(Option<&J::MetaData>) -> K::MetaData) -> K {
self.local.as_json_with(meta)
}
}
#[derive(Clone)]
pub struct Processed<'a, L: generic_json::Json, C> {
local: &'a L,
processed: C,
warnings: Vec<Loc<Warning, L::MetaData>>,
}
impl<'a, L: generic_json::Json, C> Processed<'a, L, C> {
pub fn new(local: &'a L, processed: C) -> Self {
Self::with_warnings(local, processed, Vec::new())
}
pub fn with_warnings(
local: &'a L,
processed: C,
warnings: Vec<Loc<Warning, L::MetaData>>,
) -> Self {
Processed {
local,
processed,
warnings,
}
}
pub fn warnings(&self) -> &[Loc<Warning, L::MetaData>] {
&self.warnings
}
pub fn into_inner(self) -> C {
self.processed
}
pub fn owned(self) -> ProcessedOwned<L, C>
where
L: Clone,
{
ProcessedOwned {
local: L::clone(self.local),
processed: self.processed,
warnings: self.warnings,
}
}
}
impl<'a, T: Id, L: generic_json::Json, C: ContextMut<T>> ContextMutProxy<T>
for Processed<'a, L, C>
{
type Target = C;
fn deref(&self) -> &C {
&self.processed
}
}
impl<'a, L: generic_json::Json, C> std::ops::Deref for Processed<'a, L, C> {
type Target = C;
fn deref(&self) -> &C {
&self.processed
}
}
impl<'a, L: generic_json::Json, C> std::convert::AsRef<C> for Processed<'a, L, C> {
fn as_ref(&self) -> &C {
&self.processed
}
}
impl<'a, J: JsonClone, K: JsonFrom<J>, L: generic_json::Json + AsJson<J, K>, C> AsJson<J, K>
for Processed<'a, L, C>
{
fn as_json_with(&self, meta: impl Clone + Fn(Option<&J::MetaData>) -> K::MetaData) -> K {
self.local.as_json_with(meta)
}
}
#[derive(Clone, PartialEq, Eq)]
pub struct Json<J: JsonContext, T: Id = IriBuf> {
original_base_url: Option<IriBuf>,
base_iri: Option<IriBuf>,
vocabulary: Option<Term<T>>,
default_language: Option<LenientLanguageTagBuf>,
default_base_direction: Option<Direction>,
previous_context: Option<Box<Self>>,
definitions: HashMap<String, TermDefinition<T, Self>>,
}
impl<J: JsonContext, T: Id> Json<J, T> {
pub fn new(base_iri: Option<Iri>) -> Self {
Self {
original_base_url: base_iri.map(|iri| iri.into()),
base_iri: base_iri.map(|iri| iri.into()),
vocabulary: None,
default_language: None,
default_base_direction: None,
previous_context: None,
definitions: HashMap::new(),
}
}
}
impl<J: JsonContext, T: Id> ContextMutProxy<T> for Json<J, T> {
type Target = Self;
fn deref(&self) -> &Self {
self
}
}
impl<J: JsonContext, T: Id> Default for Json<J, T> {
fn default() -> Self {
Self {
original_base_url: None,
base_iri: None,
vocabulary: None,
default_language: None,
default_base_direction: None,
previous_context: None,
definitions: HashMap::new(),
}
}
}
impl<J: JsonContext, T: Id> Context<T> for Json<J, T> {
type LocalContext = J;
fn new(base_iri: Option<Iri>) -> Self {
Self::new(base_iri)
}
fn get(&self, term: &str) -> Option<&TermDefinition<T, Self>> {
self.definitions.get(term)
}
fn original_base_url(&self) -> Option<Iri> {
self.original_base_url.as_ref().map(|iri| iri.as_iri())
}
fn base_iri(&self) -> Option<Iri> {
self.base_iri.as_ref().map(|iri| iri.as_iri())
}
fn vocabulary(&self) -> Option<&Term<T>> {
match &self.vocabulary {
Some(v) => Some(v),
None => None,
}
}
fn default_language(&self) -> Option<LenientLanguageTag> {
self.default_language.as_ref().map(|tag| tag.as_ref())
}
fn default_base_direction(&self) -> Option<Direction> {
self.default_base_direction
}
fn previous_context(&self) -> Option<&Self> {
match &self.previous_context {
Some(c) => Some(c),
None => None,
}
}
fn definitions<'a>(
&'a self,
) -> Box<dyn 'a + Iterator<Item = (&'a String, &'a TermDefinition<T, Self>)>> {
Box::new(self.definitions.iter())
}
}
impl<J: JsonContext, T: Id> ContextMut<T> for Json<J, T> {
fn set(
&mut self,
term: &str,
definition: Option<TermDefinition<T, Self>>,
) -> Option<TermDefinition<T, Self>> {
match definition {
Some(def) => self.definitions.insert(term.to_string(), def),
None => self.definitions.remove(term),
}
}
fn set_base_iri(&mut self, iri: Option<Iri>) {
self.base_iri = match iri {
Some(iri) => {
let iri_buf: IriBuf = iri.into();
Some(iri_buf)
}
None => None,
}
}
fn set_vocabulary(&mut self, vocab: Option<Term<T>>) {
self.vocabulary = vocab;
}
fn set_default_language(&mut self, lang: Option<LenientLanguageTagBuf>) {
self.default_language = lang;
}
fn set_default_base_direction(&mut self, dir: Option<Direction>) {
self.default_base_direction = dir;
}
fn set_previous_context(&mut self, previous: Self) {
self.previous_context = Some(Box::new(previous))
}
}