use core::cell::Cell;
use crate::utils;
const NON_MARKED: u32 = 0u32;
const IN_POSSIBLE_CYCLES: u32 = 1u32 << (u32::BITS - 2);
const TRACED: u32 = 2u32 << (u32::BITS - 2);
const COUNTER_MASK: u32 = 0b11111111111111u32; const TRACING_COUNTER_MASK: u32 = COUNTER_MASK << 14; const FINALIZED_MASK: u32 = 1u32 << (u32::BITS - 4);
const DROPPED_MASK: u32 = 1u32 << (u32::BITS - 3);
const BITS_MASK: u32 = !(COUNTER_MASK | TRACING_COUNTER_MASK | FINALIZED_MASK | DROPPED_MASK);
const FIRST_BIT_MASK: u32 = 1u32 << (u32::BITS - 1);
const INITIAL_VALUE: u32 = COUNTER_MASK + 2; const INITIAL_VALUE_FINALIZED: u32 = INITIAL_VALUE | FINALIZED_MASK;
pub(crate) const MAX: u32 = COUNTER_MASK;
#[derive(Clone, Debug)]
#[repr(transparent)]
pub(crate) struct CounterMarker {
    counter: Cell<u32>,
}
pub(crate) struct OverflowError;
impl CounterMarker {
    #[inline]
    #[must_use]
    pub(crate) fn new_with_counter_to_one(already_finalized: bool) -> CounterMarker {
        CounterMarker {
            counter: Cell::new(if !already_finalized {
                INITIAL_VALUE
            } else {
                INITIAL_VALUE_FINALIZED
            }),
        }
    }
    #[inline]
    pub(crate) fn increment_counter(&self) -> Result<(), OverflowError> {
        if self.counter() == MAX {
            utils::cold(); Err(OverflowError)
        } else {
            self.counter.set(self.counter.get() + 1);
            Ok(())
        }
    }
    #[inline]
    pub(crate) fn decrement_counter(&self) -> Result<(), OverflowError> {
        if self.counter() == 0 {
            utils::cold(); Err(OverflowError)
        } else {
            self.counter.set(self.counter.get() - 1);
            Ok(())
        }
    }
    #[inline]
    pub(crate) fn increment_tracing_counter(&self) -> Result<(), OverflowError> {
        if self.tracing_counter() == MAX {
            utils::cold(); Err(OverflowError)
        } else {
            self.counter.set(self.counter.get() + (1u32 << 14));
            Ok(())
        }
    }
    #[inline]
    pub(crate) fn _decrement_tracing_counter(&self) -> Result<(), OverflowError> {
        if self.tracing_counter() == 0 {
            utils::cold(); Err(OverflowError)
        } else {
            self.counter.set(self.counter.get() - (1u32 << 14));
            Ok(())
        }
    }
    #[inline]
    pub(crate) fn counter(&self) -> u32 {
        self.counter.get() & COUNTER_MASK
    }
    #[inline]
    pub(crate) fn tracing_counter(&self) -> u32 {
        (self.counter.get() & TRACING_COUNTER_MASK) >> 14
    }
    #[inline]
    pub(crate) fn reset_tracing_counter(&self) {
        self.counter.set(self.counter.get() & !TRACING_COUNTER_MASK);
    }
    #[inline]
    pub(crate) fn is_in_possible_cycles(&self) -> bool {
        (self.counter.get() & BITS_MASK) == IN_POSSIBLE_CYCLES
    }
    #[cfg(feature = "finalization")]
    #[inline]
    pub(crate) fn needs_finalization(&self) -> bool {
        (self.counter.get() & FINALIZED_MASK) == 0u32
    }
    #[cfg(feature = "finalization")]
    #[inline]
    pub(crate) fn set_finalized(&self, finalized: bool) {
        self.set_bit(finalized, FINALIZED_MASK);
    }
    #[cfg(feature = "weak-ptr")]
    #[inline]
    pub(crate) fn is_dropped(&self) -> bool {
        (self.counter.get() & DROPPED_MASK) == DROPPED_MASK
    }
    #[cfg(feature = "weak-ptr")]
    #[inline]
    pub(crate) fn set_dropped(&self, dropped: bool) {
        self.set_bit(dropped, DROPPED_MASK);
    }
    #[cfg(any(feature = "weak-ptr", feature = "finalization"))]
    #[inline(always)]
    fn set_bit(&self, value: bool, mask: u32) {
        if value {
            self.counter.set(self.counter.get() | mask);
        } else {
            self.counter.set(self.counter.get() & !mask);
        }
    }
    #[inline]
    pub(crate) fn is_not_marked(&self) -> bool {
        (self.counter.get() & FIRST_BIT_MASK) == 0u32
    }
    #[inline]
    pub(crate) fn is_traced(&self) -> bool {
        (self.counter.get() & BITS_MASK) == TRACED
    }
    #[inline]
    pub(crate) fn mark(&self, new_mark: Mark) {
        self.counter.set((self.counter.get() & !BITS_MASK) | (new_mark as u32));
    }
}
#[derive(Copy, Clone, Debug)]
#[repr(u32)]
pub(crate) enum Mark {
    NonMarked = NON_MARKED,
    PossibleCycles = IN_POSSIBLE_CYCLES,
    Traced = TRACED,
}