use indexmap::IndexMap;
use serde::{Deserialize, Serialize};
use serde_json::Value as JsonValue;
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Default)]
pub struct JsonLdHeader {
#[serde(rename = "@context", skip_serializing_if = "Option::is_none")]
pub context: Option<JsonLdContext>,
#[serde(rename = "@id", skip_serializing_if = "Option::is_none")]
pub id: Option<String>,
#[serde(rename = "@type", skip_serializing_if = "Option::is_none")]
pub type_: Option<TypeOrVec>,
}
impl JsonLdHeader {
pub fn add_term(&mut self, name: &str, term: TermDef) {
let ctx = self
.context
.get_or_insert_with(|| JsonLdContext::Object(SimpleContext::default()));
if let JsonLdContext::Object(object) = ctx {
object.terms.insert(name.to_string(), term);
}
}
pub fn update_term(&mut self, name: &str, term: TermDef) {
self.add_term(name, term);
}
pub fn remove_term(&mut self, name: &str) -> bool {
if let Some(JsonLdContext::Object(object)) = &mut self.context {
object.terms.shift_remove(name).is_some()
} else {
false
}
}
pub fn add_import(&mut self, import_url: impl Into<String>) {
let import_url = import_url.into();
match self.context.take() {
None => {
let obj = SimpleContext {
import: Some(import_url),
..Default::default()
};
self.context = Some(JsonLdContext::Object(obj));
}
Some(JsonLdContext::Object(mut obj)) => {
if obj.import.is_none() {
obj.import = Some(import_url);
self.context = Some(JsonLdContext::Object(obj));
} else {
let arr = vec![
JsonLdContext::Object(obj),
JsonLdContext::Object(SimpleContext {
import: Some(import_url),
..Default::default()
}),
];
self.context = Some(JsonLdContext::Array(arr));
}
}
Some(JsonLdContext::Iri(iri)) => {
let arr = vec![
JsonLdContext::Iri(iri),
JsonLdContext::Object(SimpleContext {
import: Some(import_url),
..Default::default()
}),
];
self.context = Some(JsonLdContext::Array(arr));
}
Some(JsonLdContext::Array(mut arr)) => {
arr.push(JsonLdContext::Object(SimpleContext {
import: Some(import_url),
..Default::default()
}));
self.context = Some(JsonLdContext::Array(arr));
}
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
#[serde(untagged)]
pub enum TypeOrVec {
Single(String),
Multi(Vec<String>),
}
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
#[serde(untagged)]
#[allow(clippy::large_enum_variant)]
pub enum JsonLdContext {
Iri(String),
Object(SimpleContext),
Array(Vec<JsonLdContext>),
}
#[derive(Debug, Clone, Serialize, Deserialize, Default, Eq, PartialEq)]
pub struct SimpleContext {
#[serde(rename = "@import", skip_serializing_if = "Option::is_none")]
pub import: Option<String>,
#[serde(rename = "@type", skip_serializing_if = "Option::is_none")]
pub type_: Option<TypeOrVec>,
#[serde(rename = "@version", skip_serializing_if = "Option::is_none")]
pub version: Option<String>,
#[serde(rename = "@base", skip_serializing_if = "Option::is_none")]
pub base: Option<Option<String>>,
#[serde(rename = "@vocab", skip_serializing_if = "Option::is_none")]
pub vocab: Option<Option<String>>,
#[serde(rename = "@language", skip_serializing_if = "Option::is_none")]
pub language: Option<Option<String>>,
#[serde(rename = "@direction", skip_serializing_if = "Option::is_none")]
pub direction: Option<String>,
#[serde(rename = "@protected", skip_serializing_if = "Option::is_none")]
pub protected: Option<bool>,
#[serde(flatten, skip_serializing_if = "IndexMap::is_empty", default)]
pub terms: IndexMap<String, TermDef>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
#[serde(untagged)]
pub enum TermDef {
Simple(String),
Detailed(TermDetail),
Null(JsonValue), }
#[derive(Debug, Clone, Serialize, Deserialize, Default, Eq, PartialEq)]
pub struct TermDetail {
#[serde(rename = "@id", skip_serializing_if = "Option::is_none")]
pub id: Option<String>,
#[serde(rename = "@type", skip_serializing_if = "Option::is_none")]
pub type_: Option<String>,
#[serde(rename = "@container", skip_serializing_if = "Option::is_none")]
pub container: Option<OneOrMany<String>>,
#[serde(rename = "@context", skip_serializing_if = "Option::is_none")]
pub context: Option<Box<JsonLdContext>>,
#[serde(rename = "@protected", skip_serializing_if = "Option::is_none")]
pub protected: Option<bool>,
#[serde(rename = "@prefix", skip_serializing_if = "Option::is_none")]
pub prefix: Option<bool>,
#[serde(rename = "@reverse", skip_serializing_if = "Option::is_none")]
pub reverse: Option<String>,
#[serde(rename = "@nest", skip_serializing_if = "Option::is_none")]
pub nest: Option<String>,
#[serde(rename = "@index", skip_serializing_if = "Option::is_none")]
pub index: Option<String>,
#[serde(rename = "@language", skip_serializing_if = "Option::is_none")]
pub language: Option<Option<String>>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
#[serde(untagged)]
pub enum OneOrMany<T> {
One(T),
Many(Vec<T>),
}
impl TermDef {
pub fn null() -> Self {
TermDef::Null(JsonValue::Null)
}
}
impl SimpleContext {
pub fn ensure_v11(mut self) -> Self {
self.version = Some("1.1".to_string());
self
}
}