use btree_indexmap::BTreeIndexSet;
use crate::{
JsonLdIndexed, JsonLdIndexedObject, JsonLdNode, JsonLdObject, JsonLdVisit,
object::{JsonLdObjectMut, JsonLdObjectRef},
};
#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct JsonLdExpandedDocument(BTreeIndexSet<JsonLdIndexedObject>);
impl JsonLdExpandedDocument {
#[inline(always)]
pub fn new() -> Self {
Self::default()
}
#[inline(always)]
pub fn len(&self) -> usize {
self.0.len()
}
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
#[inline(always)]
pub fn objects(&self) -> &BTreeIndexSet<JsonLdIndexedObject> {
&self.0
}
#[inline(always)]
pub fn into_objects(self) -> BTreeIndexSet<JsonLdIndexedObject> {
self.0
}
#[inline(always)]
pub fn iter(&self) -> btree_indexmap::set::Iter<'_, JsonLdIndexedObject> {
self.0.iter()
}
pub fn main_node(&self) -> Option<&JsonLdNode> {
let mut result = None;
for object in self {
if let JsonLdObject::Node(node) = object.inner() {
if result.is_some() {
return None;
}
result = Some(&**node)
}
}
result
}
pub fn into_main_node(self) -> Option<JsonLdNode> {
let mut result = None;
for object in self {
if let JsonLdObject::Node(node) = object.into_inner() {
if result.is_some() {
return None;
}
result = Some(*node)
}
}
result
}
#[inline(always)]
pub fn insert(&mut self, object: JsonLdIndexedObject) -> bool {
self.0.insert(object)
}
}
#[cfg(feature = "serde")]
impl JsonLdExpandedDocument {
pub fn to_json(&self) -> json_syntax::JsonValue {
json_syntax::to_value(self).expect("an expanded document is a valid JSON value")
}
}
#[cfg(feature = "serde")]
impl From<JsonLdExpandedDocument> for json_syntax::JsonValue {
fn from(document: JsonLdExpandedDocument) -> Self {
document.to_json()
}
}
impl JsonLdVisit for JsonLdExpandedDocument {
fn visit_with(&self, f: &mut impl FnMut(JsonLdObjectRef)) {
self.0.visit_with(f);
}
fn visit_mut_with(&mut self, f: &mut impl FnMut(JsonLdObjectMut)) {
self.0.visit_mut_with(f);
}
}
impl From<JsonLdIndexed<JsonLdNode>> for JsonLdExpandedDocument {
fn from(value: JsonLdIndexed<JsonLdNode>) -> Self {
let mut result = Self::default();
result.insert(value.map_inner(JsonLdObject::node));
result
}
}
impl IntoIterator for JsonLdExpandedDocument {
type IntoIter = IntoIter;
type Item = JsonLdIndexedObject;
#[inline(always)]
fn into_iter(self) -> Self::IntoIter {
IntoIter(self.0.into_iter())
}
}
impl<'a> IntoIterator for &'a JsonLdExpandedDocument {
type IntoIter = btree_indexmap::set::Iter<'a, JsonLdIndexedObject>;
type Item = &'a JsonLdIndexedObject;
#[inline(always)]
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
pub struct IntoIter(btree_indexmap::set::IntoIter<JsonLdIndexedObject>);
impl Iterator for IntoIter {
type Item = JsonLdIndexedObject;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}
impl FromIterator<JsonLdIndexedObject> for JsonLdExpandedDocument {
fn from_iter<I: IntoIterator<Item = JsonLdIndexedObject>>(iter: I) -> Self {
Self(iter.into_iter().collect())
}
}
impl Extend<JsonLdIndexedObject> for JsonLdExpandedDocument {
fn extend<I: IntoIterator<Item = JsonLdIndexedObject>>(&mut self, iter: I) {
self.0.extend(iter)
}
}
impl From<BTreeIndexSet<JsonLdIndexedObject>> for JsonLdExpandedDocument {
fn from(set: BTreeIndexSet<JsonLdIndexedObject>) -> Self {
Self(set)
}
}
#[cfg(all(test, feature = "serde"))]
mod tests {
use json_syntax::JsonValue;
use rdf_syntax::{Id, iri};
use super::*;
use crate::JsonLdLenient;
#[test]
fn empty_document_to_json() {
assert_eq!(
JsonLdExpandedDocument::new().to_json(),
JsonValue::Array(Vec::new())
);
}
#[test]
fn node_document_to_json() {
let id = JsonLdLenient::Valid(Id::Iri(iri!("https://example.org/a").to_owned()));
let document = JsonLdExpandedDocument::from(JsonLdIndexed::new(
JsonLdNode::new_with_id(Some(id)),
None,
));
let json = document.to_json();
let JsonValue::Array(objects) = &json else {
panic!("an expanded document must be a JSON array")
};
assert_eq!(objects.len(), 1);
assert_eq!(JsonValue::from(document), json);
}
}