use std::borrow::{Borrow, Cow};
use std::collections::{BTreeMap, BTreeSet};
use std::fmt::Debug;
use std::iter::once;
use slotmap::{Key, SecondaryMap};
use crate::interner::{DenseSlottedBTreeInterner, Interner};
#[derive(Clone, Debug)]
#[cfg_attr(
feature = "serde",
derive(serde::Serialize, serde::Deserialize),
serde(default, rename_all = "camelCase")
)]
#[cfg_attr(feature = "reactive", derive(reactive_stores::Store))]
pub struct Category<ObjKey, Value, FieldKey, Field>
where
ObjKey: Key,
FieldKey: Key,
Field: Clone + Debug + Ord,
{
values: SecondaryMap<ObjKey, Value>,
objects_by_field: SecondaryMap<FieldKey, BTreeSet<ObjKey>>,
field_interner: DenseSlottedBTreeInterner<FieldKey, Field>,
}
impl<ObjKey, Value, FieldKey, Field> Default for Category<ObjKey, Value, FieldKey, Field>
where
ObjKey: Key,
FieldKey: Key,
Field: Clone + Debug + Ord,
{
fn default() -> Self {
Self {
values: SecondaryMap::default(),
objects_by_field: SecondaryMap::default(),
field_interner: DenseSlottedBTreeInterner::default(),
}
}
}
impl<ObjKey, Value, FieldKey, Field> Category<ObjKey, Value, FieldKey, Field>
where
ObjKey: Key,
FieldKey: Key,
Field: Clone + Debug + Ord,
{
pub fn new() -> Self {
Self::default()
}
pub fn field_key_interned(&self, name: &Field) -> Option<FieldKey> {
self.field_interner.get_key(name)
}
pub fn field_key(&mut self, name: Cow<'_, Field>) -> FieldKey {
self.field_interner.intern(name)
}
pub fn field_name(&self, key: FieldKey) -> Option<&Field> {
self.field_interner.get_value(key)
}
pub fn num_objects(&self) -> usize {
self.values.len()
}
pub fn object_keys(&self) -> impl Iterator<Item = ObjKey> {
self.values.keys()
}
pub fn num_fields(&self) -> usize {
self.field_interner.len()
}
pub fn field_names(&self) -> impl Iterator<Item = &Field> {
self.field_interner.values()
}
pub fn field_keys(&self) -> impl Iterator<Item = FieldKey> {
self.field_interner.keys()
}
pub fn field_items(&self) -> impl Iterator<Item = (FieldKey, &Field)> {
self.field_interner.items()
}
pub fn object_value(&self, obj: ObjKey) -> Option<&Value> {
self.values.get(obj)
}
pub fn objects_with_field(&self, field: FieldKey) -> Option<&BTreeSet<ObjKey>> {
self.objects_by_field.get(field)
}
pub fn objects_with_field_name(&self, name: &Field) -> Option<&BTreeSet<ObjKey>> {
let key = self.field_key_interned(name)?;
self.objects_with_field(key)
}
pub fn contains_object(&self, obj: ObjKey) -> bool {
self.values.contains_key(obj)
}
pub fn contains_field(&self, field: FieldKey) -> bool {
self.objects_by_field.contains_key(field)
}
pub fn contains_field_name<Name: Borrow<Field>>(&self, name: Name) -> bool {
self.field_interner.contains_value(name.borrow())
}
pub fn object_contains_field(&self, obj: ObjKey, field: FieldKey) -> bool {
self.objects_with_field(field)
.map(|objs| objs.contains(&obj))
.unwrap_or_default()
}
}
impl<ObjKey, Value, FieldKey, Field> Category<ObjKey, Value, FieldKey, Field>
where
ObjKey: Key,
FieldKey: Key,
Field: Clone + Debug + Ord,
Value: FieldValue<FieldKey>,
{
pub fn clean(&mut self) {
self.values.retain(|_, fields| fields.should_retain());
let unused = self
.field_interner
.keys()
.filter(|&field| match self.objects_by_field.get(field) {
Some(objects) => objects.is_empty(),
None => true,
})
.collect::<Vec<_>>();
for field in unused {
self.objects_by_field.remove(field);
self.field_interner.remove_key(field);
}
}
fn object_value_entry(&mut self, obj: ObjKey) -> Option<&mut Value> {
self.values.entry(obj).map(|entry| entry.or_default())
}
fn objects_by_field_entry(&mut self, field: FieldKey) -> Option<&mut BTreeSet<ObjKey>> {
self.objects_by_field
.entry(field)
.map(|entry| entry.or_default())
}
pub fn remove_object(&mut self, obj: ObjKey) -> Option<Value> {
self.values.remove(obj).inspect(|value| {
value.fields().for_each(|field| {
self.remove_object_from_field_objects(field, obj);
});
})
}
fn add_object_to_field_objects(&mut self, field: FieldKey, obj: ObjKey) -> bool {
self.objects_by_field_entry(field)
.map(|objects| objects.insert(obj))
.unwrap_or_default()
}
fn remove_object_from_field_objects(&mut self, field: FieldKey, obj: ObjKey) -> bool {
let (is_empty, removed) = self
.objects_by_field
.get_mut(field)
.map(|objects| {
let removed = objects.remove(&obj);
(objects.is_empty(), removed)
})
.unwrap_or_default();
if is_empty {
self.objects_by_field.remove(field);
}
removed
}
pub fn insert_object_value(&mut self, obj: ObjKey, value: Value) {
self.remove_object(obj);
value.fields().for_each(|field| {
self.objects_by_field
.entry(field)
.map(|entry| entry.or_default().insert(obj));
});
self.values.insert(obj, value);
}
pub fn object_fields(&self, obj: ObjKey) -> impl Iterator<Item = FieldKey> {
self.values
.get(obj)
.into_iter()
.flat_map(|value| value.fields())
}
pub fn object_field_names(&self, obj: ObjKey) -> impl Iterator<Item = &Field> {
self.object_fields(obj).flat_map(|key| self.field_name(key))
}
}
impl<ObjKey, Value, FieldKey, Field> Category<ObjKey, Value, FieldKey, Field>
where
ObjKey: Key,
FieldKey: Key,
Field: Clone + Debug + Ord,
Value: FieldValue<FieldKey> + FieldWithoutSubValue<FieldKey>,
{
pub fn insert_field_name_for_object(&mut self, obj: ObjKey, name: Cow<'_, Field>) -> bool {
let field = self.field_key(name);
self.insert_field_for_object(obj, field)
}
pub fn insert_field_for_object(&mut self, obj: ObjKey, field: FieldKey) -> bool {
self.add_object_to_field_objects(field, obj);
self.object_value_entry(obj)
.map(|value| value.insert_field(field))
.unwrap_or_default()
}
pub fn remove_field_name(&mut self, name: &Field) -> Option<FieldKey> {
self.field_key_interned(name).map(|field| {
self.remove_field(field);
field
})
}
pub fn remove_field(&mut self, field: FieldKey) -> Option<Field> {
self.objects_by_field
.remove(field)
.into_iter()
.for_each(|objects| {
objects.into_iter().for_each(|obj| {
self.remove_field_from_object(obj, field);
});
});
self.field_interner.remove_key(field)
}
pub fn remove_field_name_from_object(&mut self, obj: ObjKey, field: &Field) -> bool {
self.field_key_interned(field)
.map(|field| self.remove_field_from_object(obj, field))
.unwrap_or_default()
}
pub fn remove_field_from_object(&mut self, obj: ObjKey, field: FieldKey) -> bool {
let retain = self
.values
.get_mut(obj)
.map(|value| {
value.remove_field(field);
value.should_retain()
})
.unwrap_or_default();
if !retain {
self.values.remove(obj);
}
self.remove_object_from_field_objects(field, obj)
}
}
impl<ObjKey, Value, SubValue, FieldKey, Field> Category<ObjKey, Value, FieldKey, Field>
where
ObjKey: Key,
FieldKey: Key,
Field: Clone + Debug + Ord,
Value: FieldValue<FieldKey> + FieldWithSubValue<FieldKey, SubValue = SubValue>,
{
pub fn insert_field_name_value_for_object(
&mut self,
obj: ObjKey,
field: Cow<Field>,
sub_value: SubValue,
) -> Option<SubValue> {
let field = self.field_key(field);
self.insert_field_value_for_object(obj, field, sub_value)
}
pub fn insert_field_value_for_object(
&mut self,
obj: ObjKey,
field: FieldKey,
sub_value: SubValue,
) -> Option<SubValue> {
self.add_object_to_field_objects(field, obj);
self.object_value_entry(obj)
.and_then(|value| value.insert_field_value(field, sub_value))
}
pub fn remove_field_name_values(&mut self, name: &Field) -> Option<FieldKey> {
self.field_key_interned(name).map(move |field| {
self.remove_field_values(field);
field
})
}
pub fn remove_field_values(&mut self, field: FieldKey) -> Option<Field> {
self.objects_by_field
.remove(field)
.into_iter()
.flat_map(|objects| objects.into_iter())
.for_each(|obj| {
self.remove_field_value_from_object(obj, field);
});
self.field_interner.remove_key(field)
}
pub fn remove_field_name_value_from_object(
&mut self,
obj: ObjKey,
name: &Field,
) -> Option<SubValue> {
self.field_key_interned(name)
.and_then(|field| self.remove_field_value_from_object(obj, field))
}
pub fn remove_field_value_from_object(
&mut self,
obj: ObjKey,
field: FieldKey,
) -> Option<SubValue> {
self.remove_object_from_field_objects(field, obj);
let (retain, sub_value) = self
.values
.get_mut(obj)
.map(|value| {
let sub_value = value.remove_field_value(field);
(value.should_retain(), sub_value)
})
.unwrap_or_default();
if !retain {
self.values.remove(obj);
}
sub_value
}
pub fn field_value_for_object(&self, obj: ObjKey, field: FieldKey) -> Option<&SubValue> {
self.values
.get(obj)
.and_then(|value| value.field_value(field))
}
pub fn field_name_value_for_object(&self, obj: ObjKey, field: &Field) -> Option<&SubValue> {
self.field_key_interned(field)
.and_then(|field| self.field_value_for_object(obj, field))
}
}
pub trait FieldValue<FieldKey>: Default {
fn should_retain(&self) -> bool;
fn fields(&self) -> impl Iterator<Item = FieldKey>;
}
impl<FieldKey: Key> FieldValue<FieldKey> for FieldKey {
fn should_retain(&self) -> bool {
self.is_null()
}
fn fields(&self) -> impl Iterator<Item = FieldKey> {
once(*self)
}
}
impl<FieldKey: Key> FieldValue<FieldKey> for Option<FieldKey> {
fn should_retain(&self) -> bool {
self.is_some()
}
fn fields(&self) -> impl Iterator<Item = FieldKey> {
self.iter().copied()
}
}
impl<FieldKey: Key> FieldValue<FieldKey> for BTreeSet<FieldKey> {
fn should_retain(&self) -> bool {
!self.is_empty()
}
fn fields(&self) -> impl Iterator<Item = FieldKey> {
self.iter().copied()
}
}
impl<FieldKey: Key, SubValue> FieldValue<FieldKey> for BTreeMap<FieldKey, SubValue> {
fn should_retain(&self) -> bool {
!self.is_empty()
}
fn fields(&self) -> impl Iterator<Item = FieldKey> {
self.keys().copied()
}
}
pub trait FieldWithoutSubValue<FieldKey: Key> {
fn insert_field(&mut self, field: FieldKey) -> bool;
fn remove_field(&mut self, field: FieldKey) -> bool;
}
impl<FieldKey: Key> FieldWithoutSubValue<FieldKey> for FieldKey {
fn insert_field(&mut self, mut field: FieldKey) -> bool {
if self == &field {
false
} else {
std::mem::swap(self, &mut field);
true
}
}
fn remove_field(&mut self, field: FieldKey) -> bool {
if self == &field {
std::mem::take(self);
true
} else {
false
}
}
}
impl<FieldKey: Key> FieldWithoutSubValue<FieldKey> for Option<FieldKey> {
fn insert_field(&mut self, field: FieldKey) -> bool {
if self == &Some(field) {
false
} else {
self.replace(field);
true
}
}
fn remove_field(&mut self, field: FieldKey) -> bool {
if self.as_ref() == Some(&field) {
self.take().is_some()
} else {
false
}
}
}
impl<FieldKey: Key> FieldWithoutSubValue<FieldKey> for BTreeSet<FieldKey> {
fn insert_field(&mut self, field: FieldKey) -> bool {
self.insert(field)
}
fn remove_field(&mut self, field: FieldKey) -> bool {
self.remove(&field)
}
}
impl<FieldKey: Key, SubValue: Default> FieldWithoutSubValue<FieldKey>
for BTreeMap<FieldKey, SubValue>
{
fn insert_field(&mut self, field: FieldKey) -> bool {
self.insert(field, SubValue::default()).is_none()
}
fn remove_field(&mut self, field: FieldKey) -> bool {
self.remove(&field).is_some()
}
}
pub trait FieldWithSubValue<FieldKey: Key> {
type SubValue;
fn field_value(&self, field: FieldKey) -> Option<&Self::SubValue>;
fn insert_field_value(
&mut self,
field: FieldKey,
value: Self::SubValue,
) -> Option<Self::SubValue>;
fn remove_field_value(&mut self, field: FieldKey) -> Option<Self::SubValue>;
}
impl<FieldKey: Key, SubValue> FieldWithSubValue<FieldKey> for BTreeMap<FieldKey, SubValue> {
type SubValue = SubValue;
fn field_value(&self, field: FieldKey) -> Option<&SubValue> {
self.get(&field)
}
fn insert_field_value(&mut self, field: FieldKey, value: SubValue) -> Option<SubValue> {
self.insert(field, value)
}
fn remove_field_value(&mut self, field: FieldKey) -> Option<SubValue> {
self.remove(&field)
}
}
impl<ObjKey, FieldKey, Field> Category<ObjKey, FieldKey, FieldKey, Field>
where
ObjKey: Key,
FieldKey: Key,
Field: Clone + Debug + Ord,
{
pub fn value_name_of_object(&self, obj: ObjKey) -> Option<&Field> {
let key = self.object_value(obj)?;
self.field_name(*key)
}
pub fn set_value_name_of_object(&mut self, obj: ObjKey, value: Option<Cow<Field>>) {
if let Some(field) = value {
let field = self.field_key(field);
self.insert_object_value(obj, field);
} else {
self.remove_object(obj);
}
}
}
impl<ObjKey, FieldKey, Field> Category<ObjKey, Option<FieldKey>, FieldKey, Field>
where
ObjKey: Key,
FieldKey: Key,
Field: Clone + Debug + Ord,
{
pub fn value_name_of_object(&self, obj: ObjKey) -> Option<&Field> {
let key = self.object_value(obj)?.as_ref()?;
self.field_name(*key)
}
pub fn set_value_name_of_object(&mut self, obj: ObjKey, value: Option<Cow<Field>>) {
if let Some(field) = value {
let field = self.field_key(field);
self.insert_object_value(obj, Some(field));
} else {
self.remove_object(obj);
}
}
}
impl<ObjKey, FieldKey, Field> Category<ObjKey, BTreeSet<FieldKey>, FieldKey, Field>
where
ObjKey: Key,
FieldKey: Key,
Field: Clone + Debug + Ord,
{
pub fn named_value_of_object(&self, obj: ObjKey) -> BTreeSet<&Field> {
self.object_value(obj)
.into_iter()
.flat_map(|set| set.iter())
.flat_map(|key| self.field_name(*key))
.collect()
}
}
impl<ObjKey, FieldKey, Field, SubValue>
Category<ObjKey, BTreeMap<FieldKey, SubValue>, FieldKey, Field>
where
ObjKey: Key,
FieldKey: Key,
Field: Clone + Debug + Ord,
{
pub fn named_value_of_object(&self, obj: ObjKey) -> BTreeMap<&Field, &SubValue> {
self.object_value(obj)
.into_iter()
.flat_map(|mapping| mapping.iter())
.flat_map(|(key, value)| self.field_name(*key).map(|field| (field, value)))
.collect()
}
}