use std::{ops::Deref, sync::Arc};
use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
use serde::de::DeserializeOwned;
use crate::{Error, ItemRef, Resolve};
#[derive(Debug, Clone)]
pub struct ItemRefList {
pub(crate) value: Arc<RwLock<LuaRefList>>,
}
#[derive(Debug, PartialEq, Eq)]
pub(crate) struct LuaRefList {
pub(crate) source: ItemRef,
pub(crate) refs: Vec<ItemRef>,
}
#[derive(Debug)]
pub struct RefList<'s> {
pub(crate) guard: RwLockReadGuard<'s, LuaRefList>,
}
impl<'s> RefList<'s> {
#[inline]
#[must_use]
pub fn refs(&'s self) -> &'s [ItemRef] {
&self.guard.refs
}
}
impl ItemRefList {
#[inline]
#[must_use]
pub(crate) fn new(source: ItemRef, refs: Vec<ItemRef>) -> Self {
Self {
value: Arc::new(RwLock::new(LuaRefList { source, refs })),
}
}
pub async fn keys<T>(&self) -> Result<Vec<T>, Error>
where
T: DeserializeOwned,
{
let source = &self.read().source;
source.resolve().table_keys(source).await
}
#[inline]
#[must_use]
pub fn list(&self) -> RefList<'_> {
RefList { guard: self.read() }
}
#[inline]
#[must_use]
pub fn len(&self) -> usize {
self.read().refs.len()
}
#[inline]
#[must_use]
pub unsafe fn to_vec(&mut self) -> Vec<ItemRef> {
std::mem::take(&mut self.write().refs)
}
#[inline]
pub(crate) fn read(&self) -> RwLockReadGuard<'_, LuaRefList> {
self.value.read()
}
#[inline]
pub(crate) fn write(&self) -> RwLockWriteGuard<'_, LuaRefList> {
self.value.write()
}
}
impl Drop for LuaRefList {
fn drop(&mut self) {
let mut ids = std::mem::take(&mut self.refs);
if Arc::strong_count(&self.source.value) == 1 {
let r = self.source.resolve();
let item = std::mem::replace(&mut self.source, ItemRef::phantom(r));
ids.push(item);
}
unsafe { ItemRefList::drop_all(self.source.resolve(), ids) };
}
}
impl ItemRefList {
pub unsafe fn drop_all(resolve: Resolve, refs: Vec<ItemRef>) {
let to_drop: Vec<u64> = refs
.into_iter()
.filter(|x| Arc::strong_count(&x.value) == 1 && !x.is_dropped())
.map(|x| {
*x.value
.dropped
.write()
.expect("itemref.dropped was poisoned") = true;
x.id()
})
.collect();
tokio::spawn(async move {
if let Err(e) = resolve.send_drop_items(&to_drop).await {
eprintln!("{e:?}");
}
});
}
}
impl Deref for RefList<'_> {
type Target = [ItemRef];
fn deref(&self) -> &Self::Target {
self.refs()
}
}
impl<'s> IntoIterator for &'s RefList<'s> {
type Item = &'s ItemRef;
type IntoIter = std::slice::Iter<'s, ItemRef>;
fn into_iter(self) -> Self::IntoIter {
self.refs().iter()
}
}
impl PartialEq for ItemRefList {
fn eq(&self, other: &Self) -> bool {
*self.read() == *other.read()
}
}
impl Eq for ItemRefList {}
impl PartialEq for RefList<'_> {
fn eq(&self, other: &Self) -> bool {
self.refs() == other.refs()
}
}