use crate::object::{FragmentRef, InvalidExpandedJson, Traverse};
use crate::{id, Id, Indexed, Relabel, StrippedIndexedObject};
use crate::{IndexedObject, TryFromJson};
use hashbrown::HashMap;
use locspan::{Location, Meta, StrippedEq, StrippedPartialEq};
use rdf_types::vocabulary::{Index, VocabularyMut};
use rdf_types::Vocabulary;
use std::collections::HashSet;
use std::hash::Hash;
pub struct ExpandedDocument<T = Index, B = Index, M = Location<T>>(
HashSet<StrippedIndexedObject<T, B, M>>,
);
impl<T, B, M> Default for ExpandedDocument<T, B, M> {
#[inline(always)]
fn default() -> Self {
Self(HashSet::new())
}
}
impl<T, B, M> ExpandedDocument<T, B, M> {
#[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) -> &HashSet<StrippedIndexedObject<T, B, M>> {
&self.0
}
#[inline(always)]
pub fn into_objects(self) -> HashSet<StrippedIndexedObject<T, B, M>> {
self.0
}
#[inline(always)]
pub fn iter(&self) -> std::collections::hash_set::Iter<'_, StrippedIndexedObject<T, B, M>> {
self.0.iter()
}
#[inline(always)]
pub fn traverse(&self) -> Traverse<T, B, M> {
Traverse::new(self.iter().map(|o| FragmentRef::IndexedObject(o)))
}
#[inline(always)]
pub fn count(&self, f: impl FnMut(&FragmentRef<T, B, M>) -> bool) -> usize {
self.traverse().filter(f).count()
}
#[inline(always)]
pub fn identify_all_with<V: Vocabulary<Iri = T, BlankId = B>, G: id::Generator<V, M>>(
&mut self,
vocabulary: &mut V,
generator: &mut G,
) where
M: Clone,
T: Eq + Hash,
B: Eq + Hash,
{
let mut objects = HashSet::new();
std::mem::swap(&mut self.0, &mut objects);
for mut object in objects {
object.identify_all_with(vocabulary, generator);
self.0.insert(object);
}
}
#[inline(always)]
pub fn identify_all<G: id::Generator<(), M>>(&mut self, generator: &mut G)
where
M: Clone,
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: id::Generator<V, M>,
>(
&mut self,
vocabulary: &mut V,
generator: &mut G,
) where
M: Clone,
T: Clone + Eq + Hash,
B: Clone + Eq + Hash,
{
let mut objects = HashSet::new();
std::mem::swap(&mut self.0, &mut objects);
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: id::Generator<(), M>>(&mut self, generator: &mut G)
where
M: Clone,
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: id::Generator<V, M>>(
&mut self,
vocabulary: &mut V,
generator: &mut G,
) where
M: Clone,
T: Clone + Eq + Hash,
B: Clone + Eq + Hash,
{
let mut objects = HashSet::new();
std::mem::swap(&mut self.0, &mut objects);
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: id::Generator<(), M>>(&mut self, generator: &mut G)
where
M: Clone,
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 mut objects = HashSet::new();
std::mem::swap(&mut self.0, &mut objects);
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()
}
}
impl<T: Hash + Eq, B: Hash + Eq, M> ExpandedDocument<T, B, M> {
#[inline(always)]
pub fn insert(&mut self, object: IndexedObject<T, B, M>) -> bool {
self.0.insert(locspan::Stripped(object))
}
}
impl<T: Eq + Hash, B: Eq + Hash, M> TryFromJson<T, B, M> for ExpandedDocument<T, B, M> {
fn try_from_json_in(
vocabulary: &mut impl VocabularyMut<Iri = T, BlankId = B>,
Meta(value, meta): Meta<json_syntax::Value<M>, M>,
) -> Result<Meta<Self, M>, Meta<InvalidExpandedJson<M>, M>> {
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(Meta(result, meta))
}
other => Err(Meta(
InvalidExpandedJson::Unexpected(other.kind(), json_syntax::Kind::Array),
meta,
)),
}
}
}
impl<T: Eq + Hash, B: Eq + Hash, M> PartialEq for ExpandedDocument<T, B, M> {
fn eq(&self, other: &Self) -> bool {
self.0.eq(&other.0)
}
}
impl<T: Eq + Hash, B: Eq + Hash, M> Eq for ExpandedDocument<T, B, M> {}
impl<T: Eq + Hash, B: Eq + Hash, M> StrippedPartialEq for ExpandedDocument<T, B, M> {
fn stripped_eq(&self, other: &Self) -> bool {
self.0.eq(&other.0)
}
}
impl<T: Eq + Hash, B: Eq + Hash, M> StrippedEq for ExpandedDocument<T, B, M> {}
impl<T, B, M> IntoIterator for ExpandedDocument<T, B, M> {
type IntoIter = IntoIter<T, B, M>;
type Item = IndexedObject<T, B, M>;
#[inline(always)]
fn into_iter(self) -> Self::IntoIter {
IntoIter(self.0.into_iter())
}
}
impl<'a, T, B, M> IntoIterator for &'a ExpandedDocument<T, B, M> {
type IntoIter = std::collections::hash_set::Iter<'a, StrippedIndexedObject<T, B, M>>;
type Item = &'a StrippedIndexedObject<T, B, M>;
#[inline(always)]
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
pub struct IntoIter<T, B, M>(std::collections::hash_set::IntoIter<StrippedIndexedObject<T, B, M>>);
impl<T, B, M> Iterator for IntoIter<T, B, M> {
type Item = IndexedObject<T, B, M>;
fn next(&mut self) -> Option<Self::Item> {
self.0.next().map(|s| s.0)
}
}
impl<T: Hash + Eq, B: Hash + Eq, M> FromIterator<IndexedObject<T, B, M>>
for ExpandedDocument<T, B, M>
{
fn from_iter<I: IntoIterator<Item = IndexedObject<T, B, M>>>(iter: I) -> Self {
Self(iter.into_iter().map(locspan::Stripped).collect())
}
}
impl<T: Hash + Eq, B: Hash + Eq, M> Extend<IndexedObject<T, B, M>> for ExpandedDocument<T, B, M> {
fn extend<I: IntoIterator<Item = IndexedObject<T, B, M>>>(&mut self, iter: I) {
self.0.extend(iter.into_iter().map(locspan::Stripped))
}
}
impl<T, B, M> From<HashSet<StrippedIndexedObject<T, B, M>>> for ExpandedDocument<T, B, M> {
fn from(set: HashSet<StrippedIndexedObject<T, B, M>>) -> Self {
Self(set)
}
}