use std::{
fmt::Debug,
ops::Deref,
ptr::NonNull,
sync::{Arc, Weak},
};
use crate::{Extractable, entity::EntityData};
pub struct Acquirable<T: Extractable> {
target: NonNull<T>,
pub(crate) inner: Arc<EntityData>,
}
pub struct WeakAcquirable<T: Extractable> {
inner: Weak<EntityData>,
_marker: std::marker::PhantomData<T>,
}
impl<T: Extractable> Acquirable<T> {
pub fn new(target: T) -> Self {
let data = Arc::new(EntityData::new(target, crate::get_extractor::<T>()));
Acquirable::new_raw(data.data.cast(), data)
}
pub fn new_checked<U: Extractable>(target: U) -> Acquirable<T> {
#[cfg(debug_assertions)]
const {
if !crate::ExtractionMetadata::is_has::<U, T>() {
panic!("Type U must contain T as extractable component")
}
}
let data = Arc::new(EntityData::new(target, crate::get_extractor::<U>()));
let extracted = unsafe { data.extract_ptr::<T>().unwrap_unchecked() };
Acquirable::new_raw(extracted, data)
}
#[inline(always)]
pub(crate) fn new_raw(target: NonNull<T>, inner: Arc<EntityData>) -> Self {
Self { target, inner }
}
pub fn extract_checked<U: Extractable>(&self) -> Acquirable<U> {
#[cfg(debug_assertions)]
const {
if !crate::ExtractionMetadata::is_has::<T, U>() {
panic!("Type T must contain U as extractable component")
}
}
let extracted = unsafe { self.inner.extract_ptr::<U>().unwrap_unchecked() };
Acquirable::new_raw(extracted, self.inner.clone())
}
#[inline(always)]
pub fn extract<U: Extractable>(&self) -> Option<Acquirable<U>> {
let extracted = unsafe { self.inner.extract_ptr::<U>()? };
Some(Acquirable::new_raw(extracted, self.inner.clone()))
}
#[inline(always)]
pub fn downgrade(&self) -> WeakAcquirable<T> {
WeakAcquirable {
inner: Arc::downgrade(&self.inner),
_marker: std::marker::PhantomData,
}
}
#[inline(always)]
pub fn ptr_eq<U: Extractable>(&self, other: &Acquirable<U>) -> bool {
Arc::ptr_eq(&self.inner, &other.inner)
}
#[cfg(debug_assertions)]
#[inline(always)]
pub fn strong_count(&self) -> usize {
Arc::strong_count(&self.inner)
}
#[cfg(debug_assertions)]
#[inline(always)]
pub fn weak_count(&self) -> usize {
Arc::weak_count(&self.inner)
}
}
impl<T: Extractable> WeakAcquirable<T> {
#[inline(always)]
pub fn upgrade(&self) -> Option<Acquirable<T>> {
let inner = self.inner.upgrade()?;
Some(Acquirable::new_raw(
unsafe { inner.extract_ptr::<T>().unwrap_unchecked() },
inner,
))
}
}
impl<T: Extractable> Clone for Acquirable<T> {
#[inline(always)]
fn clone(&self) -> Self {
Self {
target: self.target,
inner: self.inner.clone(),
}
}
}
impl<T: Extractable> Deref for Acquirable<T> {
type Target = T;
#[inline(always)]
fn deref(&self) -> &Self::Target {
unsafe { self.target.as_ref() }
}
}
impl<T: Extractable + Debug> Debug for Acquirable<T> {
#[inline(always)]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Acquirable")
.field("target", &**self)
.finish()
}
}
unsafe impl<T: Extractable + Send + Sync> Send for Acquirable<T> {}
unsafe impl<T: Extractable + Send + Sync> Sync for Acquirable<T> {}
impl<T: Extractable> Clone for WeakAcquirable<T> {
#[inline(always)]
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
_marker: std::marker::PhantomData,
}
}
}
unsafe impl<T: Extractable + Send + Sync> Send for WeakAcquirable<T> {}
unsafe impl<T: Extractable + Send + Sync> Sync for WeakAcquirable<T> {}