staticinit 1.0.0

Safe mutable static and non const static initialization, and code execution at program startup/exit.
Documentation
#![allow(unused)]//functions that are usefull for extension

use crate::{
    Finaly, Generator, LazySequentializer, LockNature, LockResult, Phase, Phased, Sequential,
    Sequentializer, StaticInfo, Uninit,UniqueLazySequentializer
};
use core::cell::UnsafeCell;
use core::fmt::{self, Debug, Display, Formatter};
use core::hint::unreachable_unchecked;
use core::marker::PhantomData;
use core::mem::MaybeUninit;
use core::ops::{Deref, DerefMut};

#[cfg(debug_mode)]
use crate::CyclicPanic;

#[cfg(any(feature = "parking_lot_core", debug_mode))]
use std::panic::RefUnwindSafe;

/// Policy for lazy initialization
pub(crate) trait LazyPolicy {
    /// shall the initialization be performed (tested at each access)
    fn shall_init(_: Phase) -> bool;
    /// Is the object accessible in phase `p`
    fn is_accessible(p: Phase) -> bool;
    /// Is the object accessible in phase `p`
    fn post_init_is_accessible(p: Phase) -> bool;
    /// If the object is known to already be initialized, is the object accessible in phase `p`
    fn initialized_is_accessible(p: Phase) -> bool;
}

/// Generic lazy interior data storage, uninitialized with interior mutability data storage
/// that call T::finaly when finalized
pub(crate) struct UnInited<T>(UnsafeCell<MaybeUninit<T>>);

impl<T: Finaly> Finaly for UnInited<T> {
    #[inline(always)]
    fn finaly(&self) {
        //SAFETY: UnInited is only used as part of GenericLazy, that gives access
        //only if the Sequentializer is a Lazy Sequentializer
        //
        //So the lazy Sequentializer should only execute finaly if the object initialization
        //succeeded
        unsafe { &*self.get() }.finaly();
    }
}

impl<T> UnInited<T> {
    pub const INIT: Self = Self(UnsafeCell::new(MaybeUninit::uninit()));
}

/// Generic lazy interior data storage, initialized with interior mutability data storage
/// that call T::finaly when finalized
pub(crate) struct Primed<T>(UnsafeCell<T>);

impl<T: Uninit> Finaly for Primed<T> {
    #[inline(always)]
    fn finaly(&self) {
        //SAFETY: UnInited is only used as part of GenericLazy, that gives access
        //only if the Sequentializer is a Lazy Sequentializer
        //
        //So the lazy Sequentializer should only execute finaly if the object initialization
        //succeeded
        unsafe { &mut *self.0.get() }.uninit();
    }
}

impl<T> Primed<T> {
    pub const fn prime(v: T) -> Self {
        Self(UnsafeCell::new(v))
    }
}

/// Generic lazy interior data storage, uninitialized with interior mutability data storage
/// that call drop when finalized
pub(crate) struct DropedUnInited<T>(UnsafeCell<MaybeUninit<T>>);

impl<T> Finaly for DropedUnInited<T> {
    #[inline(always)]
    fn finaly(&self) {
        //SAFETY: UnInited is only used as part of GenericLazy, that gives access
        //only if the Sequentializer is a Lazy Sequentializer
        //
        //So the lazy Sequentializer should only execute finaly if the object initialization
        //succeeded
        unsafe { self.get().drop_in_place() };
    }
}

impl<T> DropedUnInited<T> {
    pub const INIT: Self = Self(UnsafeCell::new(MaybeUninit::uninit()));
}

/// Trait implemented by generic lazy inner data.
///
/// Dereferencement of generic lazy will return a reference to
/// the inner data returned by the get method
pub(crate) trait LazyData {
    type Target;
    fn get(&self) -> *mut Self::Target;
    /// # Safety
    ///
    /// The reference to self should be unique
    unsafe fn init(&self, v: Self::Target);
    fn init_mut(&mut self, v: Self::Target);
}

impl<T> LazyData for UnInited<T> {
    type Target = T;
    #[inline(always)]
    fn get(&self) -> *mut T {
        self.0.get() as *mut T
    }
    #[inline(always)]
    unsafe fn init(&self, v: T) {
        self.get().write(v)
    }
    #[inline(always)]
    fn init_mut(&mut self, v: T) {
        *self.0.get_mut() = MaybeUninit::new(v)
    }
}

impl<T> LazyData for DropedUnInited<T> {
    type Target = T;
    #[inline(always)]
    fn get(&self) -> *mut T {
        self.0.get() as *mut T
    }
    #[inline(always)]
    unsafe fn init(&self, v: T) {
        self.get().write(v)
    }
    #[inline(always)]
    fn init_mut(&mut self, v: T) {
        *self.0.get_mut() = MaybeUninit::new(v)
    }
}

impl<T> LazyData for Primed<T> {
    type Target = T;
    #[inline(always)]
    fn get(&self) -> *mut T {
        self.0.get()
    }
    #[inline(always)]
    unsafe fn init(&self, v: T) {
        *self.get() = v
    }
    #[inline(always)]
    fn init_mut(&mut self, v: T) {
        *self.0.get_mut() = v
    }
}

/// Lazy access error
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct AccessError {
    pub phase: Phase,
}

impl Display for AccessError {
    fn fmt(&self, ft: &mut Formatter<'_>) -> fmt::Result {
        write!(ft, "Error: inaccessible lazy in {}", self.phase)
    }
}

#[cfg(feature = "parking_lot_core")]
impl std::error::Error for AccessError {}

pub(crate) struct GenericLazySeq<T, M> {
    value:          T,
    sequentializer: M,
}

pub(crate) struct GenericLockedLazySeq<T, M> {
    value:          T,
    sequentializer: M,
}

/// A type that wrap a Sequentializer and a raw data, and that may
/// initialize the data, at each access depending on the LazyPolicy
/// provided as generic argument.
pub(crate) struct GenericLazy<T, F, M, S> {
    seq:       GenericLazySeq<T, M>,
    generator: F,
    phantom:   PhantomData<S>,
    #[cfg(debug_mode)]
    _info:     Option<StaticInfo>,
}

// SAFETY: The synchronization is ensured by the Sequentializer
//  1. GenericLazy fullfill the requirement that its sequentializer is a field
//  of itself as is its target data.
//  2. The sequentializer ensure that the initialization is atomic
unsafe impl<T: LazyData, M: Sync> Sync for GenericLazySeq<T, M> where <T as LazyData>::Target: Sync {}
unsafe impl<T: LazyData, M: Sync> Send for GenericLazySeq<T, M> where <T as LazyData>::Target: Send {}

#[cfg(any(feature = "parking_lot_core", debug_mode))]
impl<T: LazyData, M: RefUnwindSafe> RefUnwindSafe for GenericLazySeq<T, M> where
    <T as LazyData>::Target: RefUnwindSafe
{
}

// SAFETY: The synchronization is ensured by the Sequentializer
//  1. GenericLazy fullfill the requirement that its sequentializer is a field
//  of itself as is its target data.
//  2. The sequentializer ensure that the initialization is atomic
unsafe impl<T: LazyData, M: Sync> Sync for GenericLockedLazySeq<T, M> where
    <T as LazyData>::Target: Send
{
}
unsafe impl<T: LazyData, M: Sync> Send for GenericLockedLazySeq<T, M> where
    <T as LazyData>::Target: Send
{
}

#[cfg(any(feature = "parking_lot_core", debug_mode))]
impl<T: LazyData, M: RefUnwindSafe> RefUnwindSafe for GenericLockedLazySeq<T, M> where
    <T as LazyData>::Target: RefUnwindSafe
{
}

impl<T, F, M, S> GenericLazy<T, F, M, S> {
    #[inline(always)]
    /// const initialize the lazy, the inner data may be in an uninitialized state
    ///
    /// # Safety
    ///
    /// ## Constraint on T
    ///
    /// Should initialize the object when init is called and the method get should
    /// return a pointer without UB if the object is not initialized
    ///
    /// ## Constraint on P
    ///
    /// The parameter M should be a lazy sequentializer that ensure that:
    ///  1. When finalize is called, no other shared reference to the inner data exist
    ///  2. The finalization is run only if the object was previously initialized
    ///
    /// ## Constraint on F
    ///
    /// The parameter F should be a Generator that ensured that the object
    /// is accessble after a call to generate succeeds
    ///
    /// ## Constraint on S
    ///
    /// S should be a lazy policy that report correctly when the object
    /// is accessbile, this in adequation with M and F.
    pub const unsafe fn new(generator: F, sequentializer: M, value: T) -> Self {
        Self {
            seq: GenericLazySeq {
                value,
                sequentializer,
            },
            generator,
            phantom: PhantomData,
            #[cfg(debug_mode)]
            _info: None,
        }
    }
    #[inline(always)]
    /// const initialize the lazy, the inner data may be in an uninitialized state
    ///
    /// # Safety
    ///
    /// ## Constraint on T
    ///
    /// Should initialize the object when init is called and the method get should
    /// return a pointer without UB if the object is not initialized
    ///
    /// ## Constraint on P
    ///
    /// The parameter M should be a lazy sequentializer that ensure that:
    ///  1. When finalize is called, no other shared reference to the inner data exist
    ///  2. The finalization is run only if the object was previously initialized
    ///
    /// ## Constraint on F
    ///
    /// The parameter F should be a Generator that ensured that the object
    /// is accessble after a call to generate succeeds
    ///
    /// ## Constraint on S
    ///
    /// S should be a lazy policy that report correctly when the object
    /// is accessbile, this in adequation with M and F.
    pub const unsafe fn new_with_info(
        generator: F,
        sequentializer: M,
        value: T,
        _info: StaticInfo,
    ) -> Self {
        Self {
            seq: GenericLazySeq {
                value,
                sequentializer,
            },
            generator,
            phantom: PhantomData,
            #[cfg(debug_mode)]
            _info: Some(_info),
        }
    }
    #[inline(always)]
    ///get access to the sequentializer
    pub fn sequentializer(this: &Self) -> &M {
        &this.seq.sequentializer
    }
    #[inline(always)]
    ///get a pointer to the raw data
    pub fn get_raw_data(this: &Self) -> &T {
        &this.seq.value
    }
}
impl<'a, T, F, M, S> GenericLazy<T, F, M, S>
where
    T: 'a + LazyData,
    M: 'a,
    M: LazySequentializer<'a, GenericLazySeq<T, M>>,
    F: 'a + Generator<T::Target>,
    S: 'a + LazyPolicy,
{
    /// Get a reference to the target
    ///
    /// # Safety
    ///
    /// Undefined behaviour if the referenced value has not been initialized
    #[inline(always)]
    pub unsafe fn get_unchecked(&'a self) -> &'a T::Target {
        &*self.seq.value.get()
    }

    /// Get a reference to the target, returning an error if the
    /// target is not in the correct phase.
    #[inline(always)]
    pub fn try_get(&'a self) -> Result<&'a T::Target, AccessError> {
        check_access::<*mut T::Target, S>(
            self.seq.value.get(),
            Phased::phase(&self.seq.sequentializer),
        )
        .map(|ptr| unsafe { &*ptr })
    }

    /// Get a reference to the target
    ///
    /// # Panics
    ///
    /// Panic if the target is not in the correct phase
    #[inline(always)]
    pub fn get(&'a self) -> &'a T::Target {
        self.try_get().unwrap()
    }

    /// Get a mutable reference to the target
    ///
    /// # Safety
    ///
    /// Undefined behaviour if the referenced value has not been initialized
    #[inline(always)]
    pub unsafe fn get_mut_unchecked(&'a mut self) -> &'a mut T::Target {
        &mut *self.seq.value.get()
    }

    /// Get a mutable reference to the target, returning an error if the
    /// target is not in the correct phase.
    #[inline(always)]
    pub fn try_get_mut(&'a mut self) -> Result<&'a mut T::Target, AccessError> {
        check_access::<*mut T::Target, S>(
            self.seq.value.get(),
            Phased::phase(&self.seq.sequentializer),
        )
        .map(|ptr| unsafe { &mut *ptr })
    }

    /// Get a reference to the target
    ///
    /// # Panics
    ///
    /// Panic if the target is not in the correct phase
    #[inline(always)]
    pub fn get_mut(&'a mut self) -> &'a mut T::Target {
        self.try_get_mut().unwrap()
    }

    /// Attempt initialization then get a reference to the target
    ///
    /// # Safety
    ///
    /// Undefined behaviour if the referenced value has not been initialized
    #[inline(always)]
    pub unsafe fn init_then_get_unchecked(&'a self) -> &'a T::Target {
        self.init();
        self.get_unchecked()
    }
    /// Attempt initialization then get a reference to the target, returning an error if the
    /// target is not in the correct phase.
    #[inline(always)]
    pub fn init_then_try_get(&'a self) -> Result<&'a T::Target, AccessError> {
        let phase = self.init();
        post_init_check_access::<*mut T::Target, S>(self.seq.value.get(), phase)
            .map(|ptr| unsafe { &*ptr })
    }
    /// Attempt initialization then get a reference to the target, returning an error if the
    /// target is not in the correct phase.
    #[inline(always)]
    pub fn init_then_get(&'a self) -> &'a T::Target {
        Self::init_then_try_get(self).unwrap()
    }
    #[inline(always)]
    /// Potentialy initialize the inner data, returning the
    /// phase reached at the end of the initialization attempt
    pub fn init(&'a self) -> Phase {
        may_debug(
            || {
                <M as LazySequentializer<'a, GenericLazySeq<T, M>>>::init(
                    &self.seq,
                    S::shall_init,
                    |data: &T| {
                        // SAFETY
                        // This function is called only once within the init function
                        // Only one thread can ever get this mutable access
                        let d = Generator::generate(&self.generator);
                        unsafe { data.init(d) };
                    },
                )
            },
            #[cfg(debug_mode)]
            &self._info,
        )
    }
}


impl<T, F, M, S> GenericLazy<T, F, M, S>
    where M: UniqueLazySequentializer<GenericLazySeq<T,M>>,
    T: LazyData,
    S: LazyPolicy,
    F: Generator<T::Target>,
{
    #[inline(always)]
    /// Attempt initialization then get a mutable reference to the target
    ///
    /// # Safety
    ///
    /// Undefined behaviour if the referenced value has not been initialized
    pub unsafe fn only_init_then_get_mut_unchecked(&mut self) -> &mut T::Target 
    {
        self.only_init_unique();
        &mut *self.seq.value.get()
    }

    #[inline(always)]
    /// Attempt initialization then get a mutable reference to the target, returning an error if the
    /// target is not in the correct phase.
    pub fn only_init_then_try_get_mut(&mut self) -> Result<&mut T::Target, AccessError>  
    {
        let phase = self.only_init_unique();
        post_init_check_access::<*mut T::Target, S>(self.seq.value.get(), phase)
            .map(|ptr| unsafe { &mut *ptr })
    }

    #[inline(always)]
    /// Attempt initialization then get a mutable reference to the target, returning an error if the
    /// target is not in the correct phase.
    pub fn only_init_then_get_mut(&mut self) -> &mut T::Target  
    {
        Self::only_init_then_try_get_mut(self).unwrap()
    }

    #[inline(always)]
    /// Potentialy initialize the inner data, returning the
    /// phase reached at the end of the initialization attempt
    pub fn only_init_unique(&mut self) -> Phase
    {
        let generator = &self.generator;
        let seq = &mut self.seq;
        <M as UniqueLazySequentializer<GenericLazySeq<T, M>>>::init_unique(
            seq,
            S::shall_init,
            |data: &mut T| {
                // SAFETY
                // This function is called only once within the init function
                // Only one thread can ever get this mutable access
                let d = Generator::generate(generator);
                unsafe { data.init_mut(d) };
            },
        )
    }
}

//SAFETY: data and sequentialize are two fields of Self.
unsafe impl<T: LazyData, M> Sequential for GenericLazySeq<T, M> {
    type Data = T;
    type Sequentializer = M;
    #[inline(always)]
    fn sequentializer(this: &Self) -> &Self::Sequentializer {
        &this.sequentializer
    }
    #[inline(always)]
    fn sequentializer_data_mut(this: &mut Self) -> (&mut Self::Sequentializer, &mut Self::Data) {
        (&mut this.sequentializer, &mut this.value)
    }
    #[inline(always)]
    fn data(this: &Self) -> &Self::Data {
        &this.value
    }
}

#[must_use="If unused the write lock is immediatly released"]
pub(crate) struct WriteGuard<T>(T);

impl<T> Deref for WriteGuard<T>
where
    T: Deref,
    <T as Deref>::Target: LazyData,
{
    type Target = <<T as Deref>::Target as LazyData>::Target;
    #[inline(always)]
    fn deref(&self) -> &Self::Target {
        unsafe { &*(*self.0).get() }
    }
}
impl<T> DerefMut for WriteGuard<T>
where
    T: Deref,
    <T as Deref>::Target: LazyData,
{
    #[inline(always)]
    fn deref_mut(&mut self) -> &mut Self::Target {
        unsafe { &mut *(*self.0).get() }
    }
}

impl<T> Phased for WriteGuard<T>
where
    T: Phased,
{
    #[inline(always)]
    fn phase(this: &Self) -> Phase {
        Phased::phase(&this.0)
    }
}

impl<T> Debug for WriteGuard<T> 
    where T: Deref,
    <T as Deref>::Target: LazyData,
    <<T as Deref>::Target as LazyData>::Target: Debug,
{
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        f.debug_tuple("WriteGuard")
            .field(&*self)
            .finish()
    }
}


#[must_use="If unused the read lock is immediatly released"]
#[derive(Clone)]
pub(crate) struct ReadGuard<T>(T);

impl<T> Deref for ReadGuard<T>
where
    T: Deref,
    <T as Deref>::Target: LazyData,
{
    type Target = <<T as Deref>::Target as LazyData>::Target;
    #[inline(always)]
    fn deref(&self) -> &Self::Target {
        unsafe { &*(*self.0).get() }
    }
}


impl<T> Debug for ReadGuard<T> 
    where T: Deref,
    <T as Deref>::Target: LazyData,
    <<T as Deref>::Target as LazyData>::Target: Debug,
{
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        f.debug_tuple("ReadGuard")
            .field(&*self)
            .finish()
    }
}

impl<T, U> From<WriteGuard<T>> for ReadGuard<U>
where
    U: From<T>,
{
    #[inline(always)]
    fn from(v: WriteGuard<T>) -> Self {
        Self(v.0.into())
    }
}

impl<T> Phased for ReadGuard<T>
where
    T: Phased,
{
    #[inline(always)]
    fn phase(this: &Self) -> Phase {
        Phased::phase(&this.0)
    }
}

#[cfg(any(feature = "parking_lot_core", debug_mode))]
impl<T: LazyData> RefUnwindSafe for ReadGuard<T> where <T as LazyData>::Target: RefUnwindSafe {}

#[cfg(any(feature = "parking_lot_core", debug_mode))]
impl<T: LazyData> RefUnwindSafe for WriteGuard<T> where <T as LazyData>::Target: RefUnwindSafe {}

/// A type that wrap a Sequentializer and a raw data, and that may
/// initialize the data, at each access depending on the LazyPolicy
/// provided as generic argument.
pub(crate) struct GenericLockedLazy<T, F, M, S> {
    seq:       GenericLockedLazySeq<T, M>,
    generator: F,
    phantom:   PhantomData<S>,
    #[cfg(debug_mode)]
    _info:     Option<StaticInfo>,
}

impl<T, F, M, S> GenericLockedLazy<T, F, M, S> {
    #[inline(always)]
    /// const initialize the lazy, the inner data may be in an uninitialized state
    ///
    /// # Safety
    ///
    /// ## Constraint on T
    ///
    /// Should initialize the object when init is called and the method get should
    /// return a pointer without UB if the object is not initialized
    ///
    /// ## Constraint on P
    ///
    /// The parameter M should be a lazy sequentializer that ensure that:
    ///  1. When finalize is called, no other shared reference to the inner data exist
    ///  2. The finalization is run only if the object was previously initialized
    ///
    /// ## Constraint on F
    ///
    /// The parameter F should be a Generator that ensured that the object
    /// is accessble after a call to generate succeeds
    ///
    /// ## Constraint on S
    ///
    /// S should be a lazy policy that report correctly when the object
    /// is accessbile, this in adequation with M and F.
    pub const unsafe fn new(generator: F, sequentializer: M, value: T) -> Self {
        Self {
            seq: GenericLockedLazySeq {
                value,
                sequentializer,
            },
            generator,
            phantom: PhantomData,
            #[cfg(debug_mode)]
            _info: None,
        }
    }
    #[inline(always)]
    /// const initialize the lazy, the inner data may be in an uninitialized state
    ///
    /// # Safety
    ///
    /// ## Constraint on T
    ///
    /// Should initialize the object when init is called and the method get should
    /// return a pointer without UB if the object is not initialized
    ///
    /// ## Constraint on P
    ///
    /// The parameter M should be a lazy sequentializer that ensure that:
    ///  1. When finalize is called, no other shared reference to the inner data exist
    ///  2. The finalization is run only if the object was previously initialized
    ///
    /// ## Constraint on F
    ///
    /// The parameter F should be a Generator that ensured that the object
    /// is accessble after a call to generate succeeds
    ///
    /// ## Constraint on S
    ///
    /// S should be a lazy policy that report correctly when the object
    /// is accessbile, this in adequation with M and F.
    pub const unsafe fn new_with_info(
        generator: F,
        sequentializer: M,
        value: T,
        _info: StaticInfo,
    ) -> Self {
        Self {
            seq: GenericLockedLazySeq {
                value,
                sequentializer,
            },
            generator,
            phantom: PhantomData,
            #[cfg(debug_mode)]
            _info: Some(_info),
        }
    }
    #[inline(always)]
    ///get access to the sequentializer
    pub fn sequentializer(this: &Self) -> &M {
        &this.seq.sequentializer
    }
}
impl<'a, T, F, M, S> GenericLockedLazy<T, F, M, S>
where
    T: 'a + LazyData,
    M: 'a,
    M: LazySequentializer<'a, GenericLockedLazySeq<T, M>>,
    F: 'a + Generator<T::Target>,
    S: 'a + LazyPolicy,
    M::ReadGuard: Phased,
    M::WriteGuard: Phased,
{
    /// Get a mutable reference to the target
    ///
    /// # Safety
    ///
    /// Undefined behaviour if the referenced value has not been initialized
    #[inline(always)]
    pub unsafe fn get_mut_unchecked(&'a mut self) -> &'a mut T::Target {
        &mut *self.seq.value.get()
    }

    /// Get a mutable reference to the target, returning an error if the
    /// target is not in the correct phase.
    #[inline(always)]
    pub fn try_get_mut(&'a mut self) -> Result<&'a mut T::Target, AccessError> {
        check_access::<*mut T::Target, S>(
            self.seq.value.get(),
            Phased::phase(&self.seq.sequentializer),
        )
        .map(|ptr| unsafe { &mut *ptr })
    }

    /// Get a reference to the target
    ///
    /// # Panics
    ///
    /// Panic if the target is not in the correct phase
    #[inline(always)]
    pub fn get_mut(&'a mut self) -> &'a mut T::Target {
        self.try_get_mut().unwrap()
    }
    /// Attempt to get a read lock the LazyData object (not the target), returning None
    /// if a unique lock is already held or in high contention cases.
    ///
    /// # Safety
    ///
    /// The obtained [ReadGuard] may reference an uninitialized target.
    #[inline(always)]
    pub unsafe fn fast_read_lock_unchecked(this: &'a Self) -> Option<ReadGuard<M::ReadGuard>> {
        <M as Sequentializer<'a, GenericLockedLazySeq<T, M>>>::try_lock(
            &this.seq,
            |_| LockNature::Read,
            M::INITIALIZED_HINT,
        )
        .map(|l| {
            if let LockResult::Read(l) = l {
                ReadGuard(l)
            } else {
                unreachable_unchecked()
            }
        })
    }
    /// Attempt to get a read lock the LazyData object (not the target), returning None
    /// if a unique lock is already held or in high contention cases.
    ///
    /// If the lock succeeds and the object is not in an accessible phase, some error is returned
    #[inline(always)]
    pub fn fast_try_read_lock(
        this: &'a Self,
    ) -> Option<Result<ReadGuard<M::ReadGuard>, AccessError>> {
        unsafe { Self::fast_read_lock_unchecked(this) }
            .map(checked_access::<ReadGuard<M::ReadGuard>, S>)
    }

    /// Attempt to get a read lock the LazyData object (not the target), returning None
    /// if a unique lock is already held or in high contention cases.
    ///
    /// # Panics
    ///
    /// Panics if the lock succeeds and the object is not in an accessible phase.
    #[inline(always)]
    pub fn fast_read_lock(this: &'a Self) -> Option<ReadGuard<M::ReadGuard>> {
        Self::fast_try_read_lock(this).map(|r| r.unwrap())
    }

    /// Get a read lock the LazyData object (not the target)
    ///
    /// # Safety
    ///
    /// The obtained [ReadGuard] may reference an uninitialized target.
    #[inline(always)]
    pub unsafe fn read_lock_unchecked(this: &'a Self) -> ReadGuard<M::ReadGuard> {
        if let LockResult::Read(l) = <M as Sequentializer<'a, GenericLockedLazySeq<T, M>>>::lock(
            &this.seq,
            |_| LockNature::Read,
            M::INITIALIZED_HINT,
        ) {
            ReadGuard(l)
        } else {
            unreachable_unchecked()
        }
    }

    /// Get a read lock the LazyData object (not the target)
    ///
    /// If the object is not in an accessible phase, some error is returned
    #[inline(always)]
    pub fn try_read_lock(this: &'a Self) -> Result<ReadGuard<M::ReadGuard>, AccessError> {
        checked_access::<ReadGuard<M::ReadGuard>, S>(unsafe { Self::read_lock_unchecked(this) })
    }

    /// Get a read lock the LazyData object (not the target).
    ///
    /// # Panics
    ///
    /// Panics if the lock succeeds and the object is not in an accessible phase.
    #[inline(always)]
    pub fn read_lock(this: &'a Self) -> ReadGuard<M::ReadGuard> {
        Self::try_read_lock(this).unwrap()
    }

    /// Attempt to get a write lock the LazyData object (not the target), returning None
    /// if a lock is already held or in high contention cases.
    ///
    /// # Safety
    ///
    /// The obtained [ReadGuard] may reference an uninitialized target.
    #[inline(always)]
    pub unsafe fn fast_write_lock_unchecked(this: &'a Self) -> Option<WriteGuard<M::WriteGuard>> {
        <M as Sequentializer<'a, GenericLockedLazySeq<T, M>>>::try_lock(
            &this.seq,
            |_| LockNature::Write,
            M::INITIALIZED_HINT,
        )
        .map(|l| {
            if let LockResult::Write(l) = l {
                WriteGuard(l)
            } else {
                unreachable_unchecked()
            }
        })
    }

    /// Attempt to get a write lock the LazyData object (not the target), returning None
    /// if a lock is already held or in high contention cases.
    ///
    /// If the lock succeeds and the object is not in an accessible phase, some error is returned
    #[inline(always)]
    pub fn fast_try_write_lock(
        this: &'a Self,
    ) -> Option<Result<WriteGuard<M::WriteGuard>, AccessError>> {
        unsafe { Self::fast_write_lock_unchecked(this) }
            .map(checked_access::<WriteGuard<M::WriteGuard>, S>)
    }

    /// Attempt to get a write lock the LazyData object (not the target), returning None
    /// if a lock is already held or in high contention cases.
    ///
    /// # Panics
    ///
    /// Panics if the lock succeeds and the object is not in an accessible phase.
    #[inline(always)]
    pub fn fast_write_lock(this: &'a Self) -> Option<WriteGuard<M::WriteGuard>> {
        Self::fast_try_write_lock(this).map(|r| r.unwrap())
    }

    /// Get a write lock the LazyData object (not the target)
    ///
    /// # Safety
    ///
    /// The obtained [ReadGuard] may reference an uninitialized target.
    #[inline(always)]
    pub unsafe fn write_lock_unchecked(this: &'a Self) -> WriteGuard<M::WriteGuard> {
        if let LockResult::Write(l) = <M as Sequentializer<'a, GenericLockedLazySeq<T, M>>>::lock(
            &this.seq,
            |_| LockNature::Write,
            M::INITIALIZED_HINT,
        ) {
            WriteGuard(l)
        } else {
            unreachable_unchecked()
        }
    }

    /// Get a read lock the LazyData object (not the target)
    ///
    /// If the object is not in an accessible phase, an error is returned
    #[inline(always)]
    pub fn try_write_lock(this: &'a Self) -> Result<WriteGuard<M::WriteGuard>, AccessError> {
        checked_access::<WriteGuard<M::WriteGuard>, S>(unsafe { Self::write_lock_unchecked(this) })
    }

    /// Get a write lock the LazyData object (not the target).
    ///
    /// # Panics
    ///
    /// Panics if the lock succeeds and the object is not in an accessible phase.
    #[inline(always)]
    pub fn write_lock(this: &'a Self) -> WriteGuard<M::WriteGuard> {
        Self::try_write_lock(this).unwrap()
    }

    #[inline(always)]
    /// Initialize if necessary then return a read lock
    ///
    /// # Safety
    ///
    /// Undefined behaviour if after initialization the return object is not in an accessible
    /// state.
    pub unsafe fn init_then_read_lock_unchecked(this: &'a Self) -> ReadGuard<M::ReadGuard> {
        let r = may_debug(
            || {
                <M as LazySequentializer<'a, GenericLockedLazySeq<T, M>>>::init_then_read_guard(
                    &this.seq,
                    S::shall_init,
                    |data: &T| {
                        // SAFETY
                        // This function is called only once within the init function
                        // Only one thread can ever get this mutable access
                        let d = Generator::generate(&this.generator);
                        #[allow(unused_unsafe)]
                        unsafe {
                            data.init(d)
                        };
                    },
                )
            },
            #[cfg(debug_mode)]
            &this._info,
        );
        ReadGuard(r)
    }

    /// Initialize if necessary then return a read lock
    ///
    /// Returns an error if after initialization the return object is not in an accessible
    /// state.
    #[inline(always)]
    pub fn init_then_try_read_lock(this: &'a Self) -> Result<ReadGuard<M::ReadGuard>, AccessError> {
        post_init_checked_access::<ReadGuard<M::ReadGuard>, S>(unsafe {
            Self::init_then_read_lock_unchecked(this)
        })
    }

    /// Initialize if necessary then return a read lock
    ///
    /// # Panics
    ///
    /// Panics if after initialization the return object is not in an accessible
    /// state.
    #[inline(always)]
    pub fn init_then_read_lock(this: &'a Self) -> ReadGuard<M::ReadGuard> {
        Self::init_then_try_read_lock(this).unwrap()
    }

    /// If necessary attempt to get a write_lock initilialize the object then turn the write
    /// lock into a read lock, otherwise attempt to get directly a read_lock. Attempt to take
    /// a lock may fail because other locks are held or because of contention.
    ///
    /// # Safety
    ///
    /// If the target is not accessible this may cause undefined behaviour.
    #[inline(always)]
    pub unsafe fn fast_init_then_read_lock_unchecked(
        this: &'a Self,
    ) -> Option<ReadGuard<M::ReadGuard>> {
        may_debug(
            || {
                <M as LazySequentializer<'a, GenericLockedLazySeq<T, M>>>::try_init_then_read_guard(
                    &this.seq,
                    S::shall_init,
                    |data: &T| {
                        // SAFETY
                        // This function is called only once within the init function
                        // Only one thread can ever get this mutable access
                        let d = Generator::generate(&this.generator);
                        #[allow(unused_unsafe)]
                        unsafe {
                            data.init(d)
                        };
                    },
                )
            },
            #[cfg(debug_mode)]
            &this._info,
        )
        .map(ReadGuard)
    }

    #[inline(always)]
    /// If necessary attempt to get a write_lock initilialize the object then turn the write
    /// lock into a read lock, otherwise attempt to get directly a read_lock. Attempt to take
    /// a lock may fail because other locks are held or because of contention.
    ///
    /// If the target is not accessible some error is returned.
    pub fn fast_init_then_try_read_lock(
        this: &'a Self,
    ) -> Option<Result<ReadGuard<M::ReadGuard>, AccessError>> {
        unsafe { Self::fast_init_then_read_lock_unchecked(this) }
            .map(post_init_checked_access::<ReadGuard<M::ReadGuard>, S>)
    }

    #[inline(always)]
    /// If necessary attempt to get a write_lock initilialize the object then turn the write
    /// lock into a read lock, otherwise attempt to get directly a read_lock. Attempt to take
    /// a lock may fail because other locks are held or because of contention.
    ///
    /// # Panics
    ///
    /// If the target is not accessible some error is returned.
    pub fn fast_init_then_read_lock(this: &'a Self) -> Option<ReadGuard<M::ReadGuard>> {
        Self::fast_init_then_try_read_lock(this).map(|r| r.unwrap())
    }

    #[inline(always)]
    /// Get a write locks, initialize the target if necessary then returns a readlock.
    ///
    /// # Safety
    ///
    /// If the target object is not accessible, this will cause undefined behaviour
    pub unsafe fn init_then_write_lock_unchecked(this: &'a Self) -> WriteGuard<M::WriteGuard> {
        let r = may_debug(
            || {
                <M as LazySequentializer<'a, GenericLockedLazySeq<T, M>>>::init_then_write_guard(
                    &this.seq,
                    S::shall_init,
                    |data: &T| {
                        // SAFETY
                        // This function is called only once within the init function
                        // Only one thread can ever get this mutable access
                        let d = Generator::generate(&this.generator);
                        #[allow(unused_unsafe)]
                        unsafe {
                            data.init(d)
                        };
                    },
                )
            },
            #[cfg(debug_mode)]
            &this._info,
        );
        WriteGuard(r)
    }

    #[inline(always)]
    /// Get a write locks, initialize the target if necessary then returns the write lock.
    ///
    /// If the target object is not accessible an error is returned.
    pub fn init_then_try_write_lock(
        this: &'a Self,
    ) -> Result<WriteGuard<M::WriteGuard>, AccessError> {
        post_init_checked_access::<WriteGuard<M::WriteGuard>, S>(unsafe {
            Self::init_then_write_lock_unchecked(this)
        })
    }
    #[inline(always)]
    /// Get a write locks, initialize the target if necessary then returns a write lock.
    ///
    /// Panics if the target object is not accessible.
    #[inline(always)]
    pub fn init_then_write_lock(this: &'a Self) -> WriteGuard<M::WriteGuard> {
        Self::init_then_try_write_lock(this).unwrap()
    }

    #[inline(always)]
    /// Attempt to get a write locks then initialize the target if necessary and returns the
    /// writelock.
    ///
    /// # Safety
    ///
    /// Undefined behavior if the target object is not accessible.
    pub unsafe fn fast_init_then_write_lock_unchecked(
        this: &'a Self,
    ) -> Option<WriteGuard<M::WriteGuard>> {
        may_debug(
            || {
                <M as LazySequentializer<'a, GenericLockedLazySeq<T, M>>>::try_init_then_write_guard(
                    &this.seq,
                    S::shall_init,
                    |data: &T| {
                        // SAFETY
                        // This function is called only once within the init function
                        // Only one thread can ever get this mutable access
                        let d = Generator::generate(&this.generator);
                        #[allow(unused_unsafe)]
                        unsafe { data.init(d) };
                    },
                )
            },
            #[cfg(debug_mode)]
            &this._info,
        )
        .map(WriteGuard)
    }
    /// Attempt to get a write locks then initialize the target if necessary and returns the
    /// writelock.
    ///
    /// Returns an error if the target object is not accessible.
    #[inline(always)]
    pub fn fast_init_then_try_write_lock(
        this: &'a Self,
    ) -> Option<Result<WriteGuard<M::WriteGuard>, AccessError>> {
        unsafe { Self::fast_init_then_write_lock_unchecked(this) }
            .map(post_init_checked_access::<WriteGuard<M::WriteGuard>, S>)
    }
    /// Attempt to get a write locks then initialize the target if necessary and returns the
    /// writelock.
    ///
    /// # Panics
    ///
    /// Panics if the target object is not accessible.
    #[inline(always)]
    pub fn fast_init_then_write_lock(this: &'a Self) -> Option<WriteGuard<M::WriteGuard>> {
        Self::fast_init_then_try_write_lock(this).map(|r| r.unwrap())
    }
}

impl<T, F, M, S> GenericLockedLazy<T, F, M, S>
    where M: UniqueLazySequentializer<GenericLockedLazySeq<T,M>>,
    T: LazyData,
    S: LazyPolicy,
    F: Generator<T::Target>,
{
    #[inline(always)]
    /// Attempt initialization then get a mutable reference to the target
    ///
    /// # Safety
    ///
    /// Undefined behaviour if the referenced value has not been initialized
    pub unsafe fn only_init_then_get_mut_unchecked(&mut self) -> &mut T::Target {
        self.only_init_unique();
        &mut *self.seq.value.get()
    }
    #[inline(always)]
    /// Attempt initialization then get a mutable reference to the target, returning an error if the
    /// target is not in the correct phase.
    pub fn only_init_then_try_get_mut(&mut self) -> Result<&mut T::Target, AccessError> {
        let phase = self.only_init_unique();
        check_access::<*mut T::Target, S>(self.seq.value.get(), phase)
            .map(|ptr| unsafe { &mut *ptr })
    }
    #[inline(always)]
    /// Attempt initialization then get a mutable reference to the target, returning an error if the
    /// target is not in the correct phase.
    pub fn only_init_then_get_mut(&mut self) -> &mut T::Target {
        Self::only_init_then_try_get_mut(self).unwrap()
    }
    #[inline(always)]
    /// Potentialy initialize the inner data, returning the
    /// phase reached at the end of the initialization attempt
    pub fn only_init_unique(&mut self) -> Phase {
        let generator = &self.generator;
        let seq = &mut self.seq;
        <M as UniqueLazySequentializer<GenericLockedLazySeq<T, M>>>::init_unique(
            seq,
            S::shall_init,
            |data: &mut T| {
                // SAFETY
                // This function is called only once within the init function
                // Only one thread can ever get this mutable access
                let d = Generator::generate(generator);
                unsafe { data.init_mut(d) };
            },
        )
    }
}

//SAFETY: data and sequentialize are two fields of Self.
unsafe impl<T: LazyData, M> Sequential for GenericLockedLazySeq<T, M> {
    type Data = T;
    type Sequentializer = M;
    #[inline(always)]
    fn sequentializer(this: &Self) -> &Self::Sequentializer {
        &this.sequentializer
    }
    #[inline(always)]
    fn sequentializer_data_mut(this: &mut Self) -> (&mut Self::Sequentializer, &mut Self::Data) {
        (&mut this.sequentializer, &mut this.value)
    }
    #[inline(always)]
    fn data(this: &Self) -> &Self::Data {
        &this.value
    }
}
impl<F, T, M, S> Deref for GenericLockedLazy<T, F, M, S> {
    type Target = T;
    #[inline(always)]
    ///get a pointer to the raw data
    fn deref(&self) -> &T {
        &self.seq.value
    }
}
impl<T, M> Deref for GenericLockedLazySeq<T, M> {
    type Target = T;
    #[inline(always)]
    ///get a pointer to the raw data
    fn deref(&self) -> &T {
        &self.value
    }
}

impl<F, T, M: Phased, S> Phased for GenericLockedLazy<T, F, M, S> {
    #[inline(always)]
    fn phase(this: &Self) -> Phase {
        Phased::phase(&this.seq.sequentializer)
    }
}
impl<F, T, M: Phased, S> Phased for GenericLazy<T, F, M, S> {
    #[inline(always)]
    fn phase(this: &Self) -> Phase {
        Phased::phase(&this.seq.sequentializer)
    }
}

#[inline(always)]
fn may_debug<R, F: FnOnce() -> R>(f: F, #[cfg(debug_mode)] info: &Option<StaticInfo>) -> R {
    #[cfg(not(debug_mode))]
    {
        f()
    }
    #[cfg(debug_mode)]
    {
        match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| f())) {
            Ok(r) => r,
            Err(x) => {
                if x.is::<CyclicPanic>() {
                    match info {
                        Some(info) => panic!("Circular initialization of {:#?}", info),
                        None => panic!("Circular lazy initialization detected"),
                    }
                } else {
                    std::panic::resume_unwind(x)
                }
            }
        }
    }
}

#[inline(always)]
fn check_access<T, S: LazyPolicy>(l: T, phase: Phase) -> Result<T, AccessError> {
    if S::is_accessible(phase) {
        Ok(l)
    } else {
        Err(AccessError { phase })
    }
}

#[inline(always)]
fn checked_access<T: Phased, S: LazyPolicy>(l: T) -> Result<T, AccessError> {
    let phase = Phased::phase(&l);
    check_access::<T, S>(l, phase)
}
#[inline(always)]
fn post_init_check_access<T, S: LazyPolicy>(l: T, phase: Phase) -> Result<T, AccessError> {
    if S::post_init_is_accessible(phase) {
        Ok(l)
    } else {
        Err(AccessError { phase })
    }
}

#[inline(always)]
fn post_init_checked_access<T: Phased, S: LazyPolicy>(l: T) -> Result<T, AccessError> {
    let phase = Phased::phase(&l);
    post_init_check_access::<T, S>(l, phase)
}