use std::sync::RwLock;
use std::{collections::HashSet, fmt::Debug, hash::Hash, marker::PhantomData};
use dashmap::{DashMap, mapref::one::Ref};
use derive_more::{Deref, DerefMut};
use intmap::IntMap;
use smart_default::SmartDefault;
use crate::prelude::*;
use crate::record::RecordMetadata;
use crate::{ImStr, format_loc};
use crate::{model::ModelName, record::Record};
use super::{_I, Symbol};
#[derive(SmartDefault, Deref)]
pub struct RecordIndex {
#[deref]
#[default(_code = "DashMap::with_shard_amount(4)")]
inner: DashMap<RecordId, Record>,
#[default(_code = "DashMap::with_shard_amount(4)")]
by_model: DashMap<ModelName, HashSet<RecordId>>,
#[default(_code = "DashMap::with_shard_amount(4)")]
by_inherit_id: DashMap<RecordId, HashSet<RecordId>>,
#[default(_code = "DashMap::with_shard_amount(4)")]
views_by_model: DashMap<ModelName, HashSet<RecordId>>,
pub by_prefix: RwLock<RecordPrefixTrie>,
}
pub type RecordId = Symbol<Record>;
pub type RecordPrefixTrie = qp_trie::Trie<ImStr, HashSet<RecordId>>;
impl RecordIndex {
pub fn insert(
&self,
qualified_id: RecordId,
record: Record,
metadata: Option<RecordMetadata>,
prefix: Option<&mut RecordPrefixTrie>,
) {
if self.inner.contains_key(&qualified_id) {
return;
}
let mut model_is_view = false;
if let Some(model) = &record.model {
self.by_model.entry(*model).or_default().insert(qualified_id);
model_is_view = _R(model) == "ir.ui.view";
}
if let Some(inherit_id) = &record.inherit_id {
self.by_inherit_id.entry(*inherit_id).or_default().insert(qualified_id);
}
if let Some(prefix) = prefix {
prefix
.entry(record.id.clone())
.or_insert_with(Default::default)
.insert(qualified_id);
} else if let Ok(mut by_prefix) = self.by_prefix.write() {
by_prefix
.entry(record.id.clone())
.or_insert_with(Default::default)
.insert(qualified_id);
}
match metadata {
Some(RecordMetadata::View(model)) if model_is_view => {
self.views_by_model
.entry(model)
.or_insert_with(Default::default)
.insert(qualified_id);
}
Some(RecordMetadata::View(_)) | None => {}
}
self.inner.insert(qualified_id, record);
}
pub fn append(&self, records: impl IntoIterator<Item = (Record, Option<RecordMetadata>)>) {
let mut prefix = self.by_prefix.write().expect(format_loc!("can't hold write lock now"));
for (record, meta) in records {
let id = _I(record.qualified_id());
self.insert(id.into(), record, meta, Some(&mut prefix));
}
}
pub fn by_model(&self, model: &ModelName) -> impl Iterator<Item = Ref<'_, RecordId, Record>> {
self.by_model
.get(model)
.into_iter()
.flat_map(|ids| self.resolve_references(ids))
}
pub fn by_inherit_id(&self, inherit_id: &RecordId) -> impl Iterator<Item = Ref<'_, RecordId, Record>> {
self.by_inherit_id
.get(inherit_id)
.into_iter()
.flat_map(|ids| self.resolve_references(ids))
}
pub fn views_by_model(&self, model: &ModelName) -> impl Iterator<Item = Ref<'_, RecordId, Record>> {
self.views_by_model
.get(model)
.into_iter()
.flat_map(|ids| self.resolve_references(ids))
}
pub fn is_target_view_model_of(&self, view_model: &ModelName, record: &RecordId) -> bool {
self.views_by_model
.get(view_model)
.is_some_and(|ids| ids.contains(record))
}
fn resolve_references<K>(
&self,
ids: Ref<K, HashSet<Symbol<Record>>>,
) -> impl IntoIterator<Item = Ref<'_, RecordId, Record>>
where
K: PartialEq + Eq + Hash,
{
ids.value()
.iter()
.flat_map(|id| self.get(id).into_iter())
.collect::<Vec<_>>()
}
}
#[derive(Deref, DerefMut)]
pub struct SymbolMap<K, T = ()>(
#[deref]
#[deref_mut]
IntMap<usize, T>,
PhantomData<K>,
);
impl<K: Debug, T: Debug> Debug for SymbolMap<K, T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_map().entries(self.0.iter()).finish()
}
}
#[derive(Deref, DerefMut)]
pub struct SymbolSet<K>(pub(crate) SymbolMap<K, ()>);
impl<K, T> Default for SymbolMap<K, T> {
#[inline]
fn default() -> Self {
Self(Default::default(), PhantomData)
}
}
impl<K> Default for SymbolSet<K> {
#[inline]
fn default() -> Self {
Self(Default::default())
}
}
impl<K, T> SymbolMap<K, T> {
#[inline]
pub fn get(&self, key: &Symbol<K>) -> Option<&T> {
self.0.get(key.into_usize())
}
#[inline]
pub fn get_mut(&mut self, key: &Symbol<K>) -> Option<&mut T> {
self.0.get_mut(key.into_usize())
}
pub fn keys(&self) -> impl Iterator<Item = Symbol<K>> + '_ {
self.0.iter().map(|(key, _)| Spur::try_from_usize(key).unwrap().into())
}
pub fn iter(&self) -> IterMap<'_, impl Iterator<Item = (usize, &T)>, K, T> {
IterMap(self.0.iter(), PhantomData)
}
}
impl<K> SymbolSet<K> {
#[inline]
pub fn insert(&mut self, key: Symbol<K>) -> bool {
self.0.0.insert_checked(key.into_usize(), ())
}
#[inline]
pub fn contains_key(&self, key: Symbol<K>) -> bool {
self.0.0.contains_key(key.into_usize() as _)
}
pub fn iter(&self) -> IterSet<'_, impl Iterator<Item = (usize, &())>, K> {
IterSet(self.0.0.iter(), PhantomData)
}
pub fn extend<I>(&mut self, items: I)
where
I: IntoIterator<Item = Symbol<K>>,
{
(self.0.0).extend(items.into_iter().map(|key| (key.into_usize(), ())));
}
}
pub struct IterMap<'a, I, K, T>(I, PhantomData<(&'a K, &'a T)>);
impl<'iter, K, T, I> Iterator for IterMap<'iter, I, K, T>
where
I: Iterator<Item = (usize, &'iter T)>,
{
type Item = (Symbol<T>, &'iter T);
fn next(&mut self) -> Option<Self::Item> {
let (next_key, next_value) = self.0.next()?;
Some((Symbol::from(Spur::try_from_usize(next_key as _).unwrap()), next_value))
}
}
pub struct IterSet<'a, I, T>(I, PhantomData<&'a T>);
impl<'iter, T, I> Iterator for IterSet<'iter, I, T>
where
I: Iterator<Item = (usize, &'iter ())>,
{
type Item = Symbol<T>;
fn next(&mut self) -> Option<Self::Item> {
let (next, ()) = self.0.next()?;
Some(Symbol::from(Spur::try_from_usize(next as _).unwrap()))
}
}