use std::{
mem::ManuallyDrop,
ptr::addr_of,
vec::{Drain, IntoIter},
};
use smallvec::SmallVec;
use crate::{
ResourceTracker,
heap::{Heap, HeapId},
value::Value,
};
pub(crate) trait HeapItem {
fn py_estimate_size(&self) -> usize;
fn py_dec_ref_ids(&mut self, stack: &mut Vec<HeapId>);
}
pub(crate) trait ContainsHeap {
type ResourceTracker: ResourceTracker;
fn heap(&self) -> &Heap<Self::ResourceTracker>;
fn heap_mut(&mut self) -> &mut Heap<Self::ResourceTracker>;
}
impl<T: ResourceTracker> ContainsHeap for Heap<T> {
type ResourceTracker = T;
fn heap(&self) -> &Self {
self
}
#[inline]
fn heap_mut(&mut self) -> &mut Self {
self
}
}
pub(crate) trait DropWithHeap: Sized {
fn drop_with_heap<H: ContainsHeap>(self, heap: &mut H);
}
impl DropWithHeap for Value {
#[inline]
fn drop_with_heap<H: ContainsHeap>(self, heap: &mut H) {
Self::drop_with_heap(self, heap);
}
}
impl<U: DropWithHeap> DropWithHeap for Option<U> {
#[inline]
fn drop_with_heap<H: ContainsHeap>(self, heap: &mut H) {
if let Some(value) = self {
value.drop_with_heap(heap);
}
}
}
impl<U: DropWithHeap> DropWithHeap for Vec<U> {
fn drop_with_heap<H: ContainsHeap>(self, heap: &mut H) {
for value in self {
value.drop_with_heap(heap);
}
}
}
impl<A: smallvec::Array> DropWithHeap for SmallVec<A>
where
A::Item: DropWithHeap,
{
fn drop_with_heap<H: ContainsHeap>(self, heap: &mut H) {
for value in self {
value.drop_with_heap(heap);
}
}
}
impl<U: DropWithHeap> DropWithHeap for IntoIter<U> {
fn drop_with_heap<H: ContainsHeap>(self, heap: &mut H) {
for value in self {
value.drop_with_heap(heap);
}
}
}
impl<U: DropWithHeap> DropWithHeap for Drain<'_, U> {
fn drop_with_heap<H: ContainsHeap>(self, heap: &mut H) {
for value in self {
value.drop_with_heap(heap);
}
}
}
impl<const N: usize> DropWithHeap for [Value; N] {
fn drop_with_heap<H: ContainsHeap>(self, heap: &mut H) {
for value in self {
value.drop_with_heap(heap);
}
}
}
impl<U: DropWithHeap, V: DropWithHeap> DropWithHeap for (U, V) {
fn drop_with_heap<H: ContainsHeap>(self, heap: &mut H) {
let (left, right) = self;
left.drop_with_heap(heap);
right.drop_with_heap(heap);
}
}
pub(crate) struct HeapGuard<'a, H: ContainsHeap, V: DropWithHeap> {
value: ManuallyDrop<V>,
heap: &'a mut H,
}
impl<'a, H: ContainsHeap, V: DropWithHeap> HeapGuard<'a, H, V> {
#[inline]
pub fn new(value: V, heap: &'a mut H) -> Self {
Self {
value: ManuallyDrop::new(value),
heap,
}
}
#[inline]
pub fn into_inner(self) -> V {
let mut this = ManuallyDrop::new(self);
unsafe { ManuallyDrop::take(&mut this.value) }
}
#[inline]
pub fn as_parts(&mut self) -> (&V, &mut H) {
(&self.value, self.heap)
}
#[inline]
pub fn as_parts_mut(&mut self) -> (&mut V, &mut H) {
(&mut self.value, self.heap)
}
#[inline]
pub fn into_parts(self) -> (V, &'a mut H) {
let mut this = ManuallyDrop::new(self);
unsafe { (ManuallyDrop::take(&mut this.value), addr_of!(this.heap).read()) }
}
#[inline]
pub fn heap(&mut self) -> &mut H {
self.heap
}
}
impl<H: ContainsHeap, V: DropWithHeap> Drop for HeapGuard<'_, H, V> {
fn drop(&mut self) {
unsafe { ManuallyDrop::take(&mut self.value) }.drop_with_heap(self.heap.heap_mut());
}
}
#[macro_export]
macro_rules! defer_drop {
($value:ident, $heap:ident) => {
let mut _guard = $crate::heap::HeapGuard::new($value, $heap);
#[allow(
clippy::allow_attributes,
reason = "the reborrowed parts may not both be used in every case, so allow unused vars to avoid warnings"
)]
#[allow(unused_variables)]
let ($value, $heap) = _guard.as_parts();
};
}
#[macro_export]
macro_rules! defer_drop_mut {
($value:ident, $heap:ident) => {
let mut _guard = $crate::heap::HeapGuard::new($value, $heap);
#[allow(
clippy::allow_attributes,
reason = "the reborrowed parts may not both be used in every case, so allow unused vars to avoid warnings"
)]
#[allow(unused_variables)]
let ($value, $heap) = _guard.as_parts_mut();
};
}