use std::any::TypeId;
use std::sync::{Arc, Weak};
use super::{
Block, BlockId, BlockMetadata, BlockRegistrationHandle, RegisteredBlock, RegisteredReturnFn,
ResetReturnFn, SequenceHash, state::Registered,
};
pub(crate) struct WeakBlockEntry<T: BlockMetadata + Sync> {
pub(crate) raw_block: Weak<Block<T, Registered>>,
pub(crate) primary_block: Weak<PrimaryBlock<T>>,
}
pub(crate) struct PrimaryBlock<T: BlockMetadata> {
block: Option<Arc<Block<T, Registered>>>,
return_fn: RegisteredReturnFn<T>,
}
pub(crate) struct DuplicateBlock<T: BlockMetadata> {
block: Option<Block<T, Registered>>,
return_fn: ResetReturnFn<T>,
_primary: Arc<PrimaryBlock<T>>,
}
impl<T: BlockMetadata + Sync> PrimaryBlock<T> {
pub(crate) fn new_attached(
block: Arc<Block<T, Registered>>,
return_fn: RegisteredReturnFn<T>,
) -> Arc<Self> {
let primary = Self {
block: Some(block),
return_fn,
};
let primary_arc = Arc::new(primary);
Self::store_weak_refs(&primary_arc);
primary_arc
}
pub(crate) fn new_unattached(
block: Arc<Block<T, Registered>>,
return_fn: RegisteredReturnFn<T>,
) -> Arc<Self> {
let primary = Self {
block: Some(block),
return_fn,
};
Arc::new(primary)
}
pub(crate) fn store_weak_refs(primary_arc: &Arc<Self>) {
let block_ref = primary_arc.block.as_ref().unwrap();
let handle = block_ref.registration_handle();
let type_id = TypeId::of::<Weak<Block<T, Registered>>>();
let raw_block = Arc::downgrade(block_ref);
let primary_block = Arc::downgrade(primary_arc);
let mut attachments = handle.inner.attachments.lock();
attachments.weak_blocks.insert(
type_id,
Box::new(WeakBlockEntry {
raw_block,
primary_block,
}),
);
}
}
impl<T: BlockMetadata> DuplicateBlock<T> {
pub(crate) fn new(
block: Block<T, Registered>,
primary: Arc<PrimaryBlock<T>>,
return_fn: ResetReturnFn<T>,
) -> Self {
Self {
block: Some(block),
return_fn,
_primary: primary,
}
}
}
impl<T: BlockMetadata> RegisteredBlock<T> for PrimaryBlock<T> {
fn block_id(&self) -> BlockId {
self.block.as_ref().unwrap().block_id()
}
fn sequence_hash(&self) -> SequenceHash {
self.block.as_ref().unwrap().sequence_hash()
}
fn registration_handle(&self) -> &BlockRegistrationHandle {
self.block.as_ref().unwrap().registration_handle()
}
}
impl<T: BlockMetadata> RegisteredBlock<T> for DuplicateBlock<T> {
fn block_id(&self) -> BlockId {
self.block.as_ref().unwrap().block_id()
}
fn sequence_hash(&self) -> SequenceHash {
self.block.as_ref().unwrap().sequence_hash()
}
fn registration_handle(&self) -> &BlockRegistrationHandle {
self.block.as_ref().unwrap().registration_handle()
}
}
impl<T: BlockMetadata> Drop for PrimaryBlock<T> {
#[inline]
fn drop(&mut self) {
if let Some(block) = self.block.take() {
(self.return_fn)(block);
}
}
}
impl<T: BlockMetadata> Drop for DuplicateBlock<T> {
#[inline]
fn drop(&mut self) {
if let Some(block) = self.block.take() {
(self.return_fn)(block.reset());
}
}
}