use super::{Multiset, Nodes};
use crate::{
object::{InvalidExpandedJson, TryFromJson, TryFromJsonObject},
Id, IndexedNode, StrippedIndexedNode,
};
use contextual::WithContext;
use derivative::Derivative;
use json_ld_syntax::IntoJsonWithContextMeta;
use locspan::{BorrowStripped, Meta, Stripped};
use rdf_types::{Vocabulary, VocabularyMut};
use std::hash::{Hash, Hasher};
pub use super::properties::Entry;
pub type ReversePropertyNodes<T, B, M> = Multiset<Stripped<IndexedNode<T, B, M>>>;
#[derive(Derivative, Clone)]
#[derivative(
PartialEq(bound = "T: Eq + Hash, B: Eq + Hash, M: PartialEq"),
Eq(bound = "T: Eq + Hash, B: Eq + Hash, M: Eq")
)]
pub struct ReverseProperties<T, B, M>(hashbrown::HashMap<Id<T, B>, ReversePropertyEntry<T, B, M>>);
impl<T, B, M> ReverseProperties<T, B, M> {
pub(crate) fn new() -> Self {
Self(hashbrown::HashMap::new())
}
#[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 iter(&self) -> Iter<'_, T, B, M> {
Iter {
inner: self.0.iter(),
}
}
#[inline(always)]
pub fn iter_mut(&mut self) -> IterMut<'_, T, B, M> {
IterMut {
inner: self.0.iter_mut(),
}
}
#[inline(always)]
pub fn clear(&mut self) {
self.0.clear()
}
}
impl<T: Eq + Hash, B: Eq + Hash, M> ReverseProperties<T, B, M> {
#[inline(always)]
pub fn contains<Q: ?Sized + Hash + hashbrown::Equivalent<Id<T, B>>>(&self, prop: &Q) -> bool {
self.0.get(prop).is_some()
}
#[inline(always)]
pub fn get<'a, Q: ?Sized + Hash + hashbrown::Equivalent<Id<T, B>>>(
&self,
prop: &Q,
) -> Nodes<T, B, M>
where
T: 'a,
{
match self.0.get(prop) {
Some(values) => Nodes::new(Some(values.iter())),
None => Nodes::new(None),
}
}
#[inline(always)]
pub fn get_any<'a, Q: ?Sized + Hash + hashbrown::Equivalent<Id<T, B>>>(
&self,
prop: &Q,
) -> Option<&IndexedNode<T, B, M>>
where
T: 'a,
{
match self.0.get(prop) {
Some(values) => values.iter().next().map(|n| &n.0),
None => None,
}
}
#[inline(always)]
pub fn insert(&mut self, Meta(prop, meta): Meta<Id<T, B>, M>, value: IndexedNode<T, B, M>) {
if let Some(node_values) = self.0.get_mut(&prop) {
node_values.insert(Stripped(value));
} else {
self.0
.insert(prop, Entry::new(meta, Multiset::singleton(Stripped(value))));
}
}
#[inline(always)]
pub fn insert_unique(
&mut self,
Meta(prop, meta): Meta<Id<T, B>, M>,
value: IndexedNode<T, B, M>,
) {
if let Some(node_values) = self.0.get_mut(&prop) {
if node_values.iter().all(|v| !v.equivalent(&value)) {
node_values.insert(Stripped(value))
}
} else {
self.0
.insert(prop, Entry::new(meta, Multiset::singleton(Stripped(value))));
}
}
#[inline(always)]
pub fn insert_all<Objects: IntoIterator<Item = IndexedNode<T, B, M>>>(
&mut self,
Meta(prop, meta): Meta<Id<T, B>, M>,
values: Objects,
) {
if let Some(node_values) = self.0.get_mut(&prop) {
node_values.extend(values.into_iter().map(Stripped));
} else {
self.0.insert(
prop,
Entry::new(meta, values.into_iter().map(Stripped).collect()),
);
}
}
#[inline(always)]
pub fn insert_all_unique_stripped<
Nodes: IntoIterator<Item = Stripped<IndexedNode<T, B, M>>>,
>(
&mut self,
Meta(prop, meta): Meta<Id<T, B>, M>,
values: Nodes,
) {
if let Some(node_values) = self.0.get_mut(&prop) {
for value in values {
if node_values.iter().all(|v| !v.equivalent(&value)) {
node_values.insert(value)
}
}
} else {
let values = values.into_iter();
let mut node_values: ReversePropertyNodes<T, B, M> =
Multiset::with_capacity(values.size_hint().0);
for value in values {
if node_values.iter().all(|v| !v.equivalent(&value)) {
node_values.insert(value)
}
}
self.0.insert(prop, Entry::new(meta, node_values));
}
}
#[inline(always)]
pub fn insert_all_unique<Nodes: IntoIterator<Item = IndexedNode<T, B, M>>>(
&mut self,
prop: Meta<Id<T, B>, M>,
values: Nodes,
) {
self.insert_all_unique_stripped(prop, values.into_iter().map(Stripped))
}
pub fn extend_unique<I, N>(&mut self, iter: I)
where
I: IntoIterator<Item = (Meta<Id<T, B>, M>, N)>,
N: IntoIterator<Item = IndexedNode<T, B, M>>,
{
for (prop, values) in iter {
self.insert_all_unique(prop, values)
}
}
pub fn extend_unique_stripped<I, N>(&mut self, iter: I)
where
I: IntoIterator<Item = (Meta<Id<T, B>, M>, N)>,
N: IntoIterator<Item = Stripped<IndexedNode<T, B, M>>>,
{
for (prop, values) in iter {
self.insert_all_unique_stripped(prop, values)
}
}
#[inline(always)]
pub fn remove(&mut self, prop: &Id<T, B>) -> Option<ReversePropertyEntry<T, B, M>> {
self.0.remove(prop)
}
}
impl<T: Eq + Hash, B: Eq + Hash, M> TryFromJson<T, B, M> for ReverseProperties<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::Object(object) => {
Self::try_from_json_object_in(vocabulary, Meta(object, meta))
}
_ => Err(Meta(InvalidExpandedJson::InvalidObject, meta)),
}
}
}
impl<T: Eq + Hash, B: Eq + Hash, M> TryFromJsonObject<T, B, M> for ReverseProperties<T, B, M> {
fn try_from_json_object_in(
vocabulary: &mut impl VocabularyMut<Iri = T, BlankId = B>,
Meta(object, meta): Meta<json_syntax::Object<M>, M>,
) -> Result<Meta<Self, M>, Meta<InvalidExpandedJson<M>, M>> {
let mut result = Self::new();
for entry in object {
let Meta(key, key_meta) = entry.key;
let prop = Id::from_string_in(vocabulary, key.to_string());
let nodes: Vec<IndexedNode<T, B, M>> =
Vec::try_from_json_in(vocabulary, entry.value)?.into_value();
result.insert_all(Meta(prop, key_meta), nodes)
}
Ok(Meta(result, meta))
}
}
impl<T: Eq + Hash, B: Eq + Hash, M> locspan::StrippedPartialEq for ReverseProperties<T, B, M> {
#[inline(always)]
fn stripped_eq(&self, other: &Self) -> bool {
self.0.stripped() == other.0.stripped()
}
}
impl<T: Eq + Hash, B: Eq + Hash, M> locspan::StrippedEq for ReverseProperties<T, B, M> {}
impl<T: Hash, B: Hash, M> locspan::StrippedHash for ReverseProperties<T, B, M> {
#[inline(always)]
fn stripped_hash<H: Hasher>(&self, h: &mut H) {
crate::utils::hash_map_stripped(&self.0, h)
}
}
impl<T: Hash, B: Hash, M: Hash> Hash for ReverseProperties<T, B, M> {
#[inline(always)]
fn hash<H: Hasher>(&self, h: &mut H) {
crate::utils::hash_map(&self.0, h)
}
}
impl<T: Eq + Hash, B: Eq + Hash, M> Extend<(Meta<Id<T, B>, M>, Vec<IndexedNode<T, B, M>>)>
for ReverseProperties<T, B, M>
{
fn extend<I>(&mut self, iter: I)
where
I: IntoIterator<Item = (Meta<Id<T, B>, M>, Vec<IndexedNode<T, B, M>>)>,
{
for (prop, values) in iter {
self.insert_all(prop, values)
}
}
}
pub type ReverseBinding<T, B, M> = (Meta<Id<T, B>, M>, ReversePropertyNodes<T, B, M>);
pub type ReverseBindingRef<'a, T, B, M> = (
Meta<&'a Id<T, B>, &'a M>,
&'a [StrippedIndexedNode<T, B, M>],
);
pub type ReverseBindingMut<'a, T, B, M> = (
Meta<&'a Id<T, B>, &'a mut M>,
&'a mut ReversePropertyNodes<T, B, M>,
);
impl<T, B, M> IntoIterator for ReverseProperties<T, B, M> {
type Item = ReverseBinding<T, B, M>;
type IntoIter = IntoIter<T, B, M>;
#[inline(always)]
fn into_iter(self) -> Self::IntoIter {
IntoIter {
inner: self.0.into_iter(),
}
}
}
impl<'a, T, B, M> IntoIterator for &'a ReverseProperties<T, B, M> {
type Item = ReverseBindingRef<'a, T, B, M>;
type IntoIter = Iter<'a, T, B, M>;
#[inline(always)]
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a, T, B, M> IntoIterator for &'a mut ReverseProperties<T, B, M> {
type Item = ReverseBindingMut<'a, T, B, M>;
type IntoIter = IterMut<'a, T, B, M>;
#[inline(always)]
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}
pub struct IntoIter<T, B, M> {
inner: hashbrown::hash_map::IntoIter<Id<T, B>, ReversePropertyEntry<T, B, M>>,
}
impl<T, B, M> Iterator for IntoIter<T, B, M> {
type Item = ReverseBinding<T, B, M>;
#[inline(always)]
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
#[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
self.inner
.next()
.map(|(k, v)| (Meta(k, v.key_metadata), v.value))
}
}
impl<T, B, M> ExactSizeIterator for IntoIter<T, B, M> {}
impl<T, B, M> std::iter::FusedIterator for IntoIter<T, B, M> {}
#[derive(Derivative)]
#[derivative(Clone(bound = ""))]
pub struct Iter<'a, T, B, M> {
inner: hashbrown::hash_map::Iter<'a, Id<T, B>, ReversePropertyEntry<T, B, M>>,
}
impl<'a, T, B, M> Iterator for Iter<'a, T, B, M> {
type Item = ReverseBindingRef<'a, T, B, M>;
#[inline(always)]
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
#[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
self.inner.next().map(|(property, objects)| {
(
Meta(property, &objects.key_metadata),
objects.value.as_slice(),
)
})
}
}
impl<'a, T, B, M> ExactSizeIterator for Iter<'a, T, B, M> {}
impl<'a, T, B, M> std::iter::FusedIterator for Iter<'a, T, B, M> {}
pub type ReversePropertyEntry<T, B, M> = Entry<ReversePropertyNodes<T, B, M>, M>;
pub struct IterMut<'a, T, B, M> {
inner: hashbrown::hash_map::IterMut<'a, Id<T, B>, ReversePropertyEntry<T, B, M>>,
}
impl<'a, T, B, M> Iterator for IterMut<'a, T, B, M> {
type Item = ReverseBindingMut<'a, T, B, M>;
#[inline(always)]
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
#[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
self.inner
.next()
.map(|(k, v)| (Meta(k, &mut v.key_metadata), &mut v.value))
}
}
impl<'a, T, B, M> ExactSizeIterator for IterMut<'a, T, B, M> {}
impl<'a, T, B, M> std::iter::FusedIterator for IterMut<'a, T, B, M> {}
impl<T, B, M: Clone, N: Vocabulary<Iri = T, BlankId = B>> IntoJsonWithContextMeta<M, N>
for ReverseProperties<T, B, M>
{
fn into_json_meta_with(self, meta: M, vocabulary: &N) -> Meta<json_syntax::Value<M>, M> {
let mut obj = json_syntax::Object::new();
for (Meta(prop, meta), nodes) in self {
obj.insert(
Meta(prop.with(vocabulary).to_string().into(), meta.clone()),
nodes.into_json_meta_with(meta, vocabulary),
);
}
Meta(obj.into(), meta)
}
}