use crate::object::{FragmentRef, InvalidExpandedJson, Traverse};
use crate::{Id, Indexed, IndexedObject, Node, Object, Relabel, TryFromJson};
use hashbrown::HashMap;
use indexmap::IndexSet;
use iref::IriBuf;
use rdf_types::vocabulary::VocabularyMut;
use rdf_types::{BlankIdBuf, Generator, Vocabulary};
use std::collections::HashSet;
use std::hash::Hash;
#[derive(Debug, Clone)]
pub struct ExpandedDocument<T = IriBuf, B = BlankIdBuf>(IndexSet<IndexedObject<T, B>>);
impl<T, B> Default for ExpandedDocument<T, B> {
#[inline(always)]
fn default() -> Self {
Self(IndexSet::new())
}
}
impl<T, B> ExpandedDocument<T, B> {
#[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) -> &IndexSet<IndexedObject<T, B>> {
&self.0
}
#[inline(always)]
pub fn into_objects(self) -> IndexSet<IndexedObject<T, B>> {
self.0
}
#[inline(always)]
pub fn iter(&self) -> indexmap::set::Iter<'_, IndexedObject<T, B>> {
self.0.iter()
}
#[inline(always)]
pub fn traverse(&self) -> Traverse<T, B> {
Traverse::new(self.iter().map(|o| FragmentRef::IndexedObject(o)))
}
#[inline(always)]
pub fn count(&self, f: impl FnMut(&FragmentRef<T, B>) -> bool) -> usize {
self.traverse().filter(f).count()
}
#[inline(always)]
pub fn identify_all_with<V: Vocabulary<Iri = T, BlankId = B>, G: Generator<V>>(
&mut self,
vocabulary: &mut V,
generator: &mut G,
) where
T: Eq + Hash,
B: Eq + Hash,
{
let objects = std::mem::take(&mut self.0);
for mut object in objects {
object.identify_all_with(vocabulary, generator);
self.0.insert(object);
}
}
#[inline(always)]
pub fn identify_all<G: Generator>(&mut self, generator: &mut G)
where
T: Eq + Hash,
B: Eq + Hash,
(): Vocabulary<Iri = T, BlankId = B>,
{
self.identify_all_with(&mut (), generator)
}
#[inline(always)]
pub fn relabel_and_canonicalize_with<V: Vocabulary<Iri = T, BlankId = B>, G: Generator<V>>(
&mut self,
vocabulary: &mut V,
generator: &mut G,
) where
T: Clone + Eq + Hash,
B: Clone + Eq + Hash,
{
let objects = std::mem::take(&mut self.0);
let mut relabeling = HashMap::new();
let mut buffer = ryu_js::Buffer::new();
for mut object in objects {
object.relabel_with(vocabulary, generator, &mut relabeling);
object.canonicalize_with(&mut buffer);
self.0.insert(object);
}
}
#[inline(always)]
pub fn relabel_and_canonicalize<G: Generator>(&mut self, generator: &mut G)
where
T: Clone + Eq + Hash,
B: Clone + Eq + Hash,
(): Vocabulary<Iri = T, BlankId = B>,
{
self.relabel_and_canonicalize_with(&mut (), generator)
}
#[inline(always)]
pub fn relabel_with<V: Vocabulary<Iri = T, BlankId = B>, G: Generator<V>>(
&mut self,
vocabulary: &mut V,
generator: &mut G,
) where
T: Clone + Eq + Hash,
B: Clone + Eq + Hash,
{
let objects = std::mem::take(&mut self.0);
let mut relabeling = HashMap::new();
for mut object in objects {
object.relabel_with(vocabulary, generator, &mut relabeling);
self.0.insert(object);
}
}
#[inline(always)]
pub fn relabel<G: Generator>(&mut self, generator: &mut G)
where
T: Clone + Eq + Hash,
B: Clone + Eq + Hash,
(): Vocabulary<Iri = T, BlankId = B>,
{
self.relabel_with(&mut (), generator)
}
pub fn canonicalize_with(&mut self, buffer: &mut ryu_js::Buffer)
where
T: Eq + Hash,
B: Eq + Hash,
{
let objects = std::mem::take(&mut self.0);
for mut object in objects {
object.canonicalize_with(buffer);
self.0.insert(object);
}
}
pub fn canonicalize(&mut self)
where
T: Eq + Hash,
B: Eq + Hash,
{
let mut buffer = ryu_js::Buffer::new();
self.canonicalize_with(&mut buffer)
}
pub fn blank_ids(&self) -> HashSet<&B>
where
B: Eq + Hash,
{
self.traverse()
.filter_map(|f| f.into_id().and_then(Id::into_blank))
.collect()
}
pub fn main_node(&self) -> Option<&Node<T, B>> {
let mut result = None;
for object in self {
if let Object::Node(node) = object.inner() {
if result.is_some() {
return None;
}
result = Some(&**node)
}
}
result
}
pub fn into_main_node(self) -> Option<Node<T, B>> {
let mut result = None;
for object in self {
if let Object::Node(node) = object.into_inner() {
if result.is_some() {
return None;
}
result = Some(*node)
}
}
result
}
}
impl<T: Hash + Eq, B: Hash + Eq> ExpandedDocument<T, B> {
#[inline(always)]
pub fn insert(&mut self, object: IndexedObject<T, B>) -> bool {
self.0.insert(object)
}
}
impl<T: Eq + Hash, B: Eq + Hash> From<Indexed<Node<T, B>>> for ExpandedDocument<T, B> {
fn from(value: Indexed<Node<T, B>>) -> Self {
let mut result = Self::default();
result.insert(value.map_inner(Object::node));
result
}
}
impl<T: Eq + Hash, B: Eq + Hash> TryFromJson<T, B> for ExpandedDocument<T, B> {
fn try_from_json_in(
vocabulary: &mut impl VocabularyMut<Iri = T, BlankId = B>,
value: json_syntax::Value,
) -> Result<Self, InvalidExpandedJson> {
match value {
json_syntax::Value::Array(items) => {
let mut result = Self::new();
for item in items {
result.insert(Indexed::try_from_json_in(vocabulary, item)?);
}
Ok(result)
}
other => Err(InvalidExpandedJson::Unexpected(
other.kind(),
json_syntax::Kind::Array,
)),
}
}
}
impl<T: Eq + Hash, B: Eq + Hash> PartialEq for ExpandedDocument<T, B> {
fn eq(&self, other: &Self) -> bool {
self.0.eq(&other.0)
}
}
impl<T: Eq + Hash, B: Eq + Hash> Eq for ExpandedDocument<T, B> {}
impl<T, B> IntoIterator for ExpandedDocument<T, B> {
type IntoIter = IntoIter<T, B>;
type Item = IndexedObject<T, B>;
#[inline(always)]
fn into_iter(self) -> Self::IntoIter {
IntoIter(self.0.into_iter())
}
}
impl<'a, T, B> IntoIterator for &'a ExpandedDocument<T, B> {
type IntoIter = indexmap::set::Iter<'a, IndexedObject<T, B>>;
type Item = &'a IndexedObject<T, B>;
#[inline(always)]
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
pub struct IntoIter<T, B>(indexmap::set::IntoIter<IndexedObject<T, B>>);
impl<T, B> Iterator for IntoIter<T, B> {
type Item = IndexedObject<T, B>;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}
impl<T: Hash + Eq, B: Hash + Eq> FromIterator<IndexedObject<T, B>> for ExpandedDocument<T, B> {
fn from_iter<I: IntoIterator<Item = IndexedObject<T, B>>>(iter: I) -> Self {
Self(iter.into_iter().collect())
}
}
impl<T: Hash + Eq, B: Hash + Eq> Extend<IndexedObject<T, B>> for ExpandedDocument<T, B> {
fn extend<I: IntoIterator<Item = IndexedObject<T, B>>>(&mut self, iter: I) {
self.0.extend(iter)
}
}
impl<T, B> From<IndexSet<IndexedObject<T, B>>> for ExpandedDocument<T, B> {
fn from(set: IndexSet<IndexedObject<T, B>>) -> Self {
Self(set)
}
}