use core::cell::Cell;
use core::mem;
use core::mem::ManuallyDrop;
use core::ops::Deref;
use core::ops::DerefMut;
#[cfg(doc)]
use {
crate::move_ref::{DerefMove, MoveRef},
alloc::boxed::Box,
core::pin::Pin,
};
#[derive(Clone, Copy)]
pub struct DropFlag<'frame> {
counter: &'frame Cell<usize>,
}
impl DropFlag<'_> {
#[inline]
pub fn inc(self) {
self.counter.set(self.counter.get() + 1)
}
#[inline]
pub fn dec_and_check_if_died(self) -> bool {
if self.counter.get() == 0 {
return false;
}
self.counter.set(self.counter.get() - 1);
self.is_dead()
}
#[inline]
pub fn is_dead(self) -> bool {
self.counter.get() == 0
}
#[inline]
#[allow(unused)]
pub(crate) unsafe fn longer_lifetime<'a>(self) -> DropFlag<'a> {
DropFlag {
counter: mem::transmute(self.counter),
}
}
}
pub struct DroppingFlag<T> {
value: ManuallyDrop<T>,
counter: Cell<usize>,
}
impl<T> DroppingFlag<T> {
pub fn new(value: T) -> Self {
Self {
value: ManuallyDrop::new(value),
counter: Cell::new(0),
}
}
pub fn flag(slot: &Self) -> DropFlag {
DropFlag {
counter: &slot.counter,
}
}
pub fn as_parts(slot: &Self) -> (&T, DropFlag) {
(
&slot.value,
DropFlag {
counter: &slot.counter,
},
)
}
pub fn as_parts_mut(slot: &mut Self) -> (&mut T, DropFlag) {
(
&mut slot.value,
DropFlag {
counter: &slot.counter,
},
)
}
}
impl<T> Deref for DroppingFlag<T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
&self.value
}
}
impl<T> DerefMut for DroppingFlag<T> {
#[inline]
fn deref_mut(&mut self) -> &mut T {
&mut self.value
}
}
impl<T> Drop for DroppingFlag<T> {
fn drop(&mut self) {
if Self::flag(self).is_dead() {
unsafe {
ManuallyDrop::drop(&mut self.value);
}
}
}
}
pub struct TrappedFlag {
counter: Cell<usize>,
#[cfg(debug_assertions)]
location: &'static core::panic::Location<'static>,
}
impl TrappedFlag {
#[cfg(debug_assertions)]
#[track_caller]
pub fn new() -> Self {
Self {
counter: Cell::new(0),
location: core::panic::Location::caller(),
}
}
#[cfg(not(debug_assertions))]
pub fn new() -> Self {
Self {
counter: Cell::new(0),
}
}
pub fn flag(&self) -> DropFlag {
DropFlag {
counter: &self.counter,
}
}
pub fn assert_cleared(&self) {
if self.flag().is_dead() {
return;
}
struct DoublePanic;
impl Drop for DoublePanic {
fn drop(&mut self) {
if cfg!(not(test)) {
panic!()
}
}
}
let _dp = DoublePanic;
#[cfg(debug_assertions)]
panic!("a critical drop flag at {} was not cleared!", self.location);
#[cfg(not(debug_assertions))]
panic!("a critical drop flag was not cleared!");
}
}
impl Default for TrappedFlag {
fn default() -> Self {
Self::new()
}
}
impl Drop for TrappedFlag {
fn drop(&mut self) {
self.assert_cleared();
}
}
pub struct QuietFlag {
counter: Cell<usize>,
}
impl QuietFlag {
pub fn new() -> Self {
Self {
counter: Cell::new(0),
}
}
pub fn flag(&self) -> DropFlag {
DropFlag {
counter: &self.counter,
}
}
}
impl Default for QuietFlag {
fn default() -> Self {
Self::new()
}
}