rt 0.19.1

A real-time operating system capable of full preemption
Documentation
use core::{
    cell::UnsafeCell,
    mem::ManuallyDrop,
    ops::Deref,
    panic::{RefUnwindSafe, UnwindSafe},
};

use crate::{ptr_macros::ptr_to_field, sync::Once};

union Data<T, F> {
    value: ManuallyDrop<T>,
    f: ManuallyDrop<F>,
}

pub struct LazyLock<T, F = fn() -> T> {
    once: Once,
    data: UnsafeCell<Data<T, F>>,
}

impl<T, F: FnOnce() -> T> LazyLock<T, F> {
    /// Initialize a new `LazyLock`.
    ///
    /// # Safety
    ///
    /// This must be called with a pointer to a `static` `LazyLock` and be used to initialize that
    /// same `LazyLock`. Users should use the `rt::sync::lazy_lock!` macro to create a `LazyLock`
    /// rather than call `LazyLock::init` directly.
    #[must_use]
    pub const unsafe fn init(this: *const Self, f: F) -> LazyLock<T, F> {
        let once_ptr = ptr_to_field!(this, once);
        LazyLock {
            once: unsafe { Once::init(once_ptr) },
            data: UnsafeCell::new(Data {
                f: ManuallyDrop::new(f),
            }),
        }
    }

    pub fn force(&self) -> &T {
        self.once.call_once(|| {
            let data = unsafe { &mut *self.data.get() };
            let f = unsafe { ManuallyDrop::take(&mut data.f) };
            let value = f();
            data.value = ManuallyDrop::new(value);
        });
        unsafe { &(*self.data.get()).value }
    }
}

impl<T, F: FnOnce() -> T> Deref for LazyLock<T, F> {
    type Target = T;
    #[inline]
    fn deref(&self) -> &T {
        self.force()
    }
}

// We never create a `&F` from a `&LazyLock<T, F>` so it is fine
// to not impl `Sync` for `F`.
unsafe impl<T: Sync + Send, F: Send> Sync for LazyLock<T, F> {}
// auto-derived `Send` impl is OK.

impl<T: RefUnwindSafe + UnwindSafe, F: UnwindSafe> RefUnwindSafe for LazyLock<T, F> {}
impl<T: UnwindSafe, F: UnwindSafe> UnwindSafe for LazyLock<T, F> {}

#[macro_export]
macro_rules! lazy_lock {
    ($name: ident, $type: ty, $fn: expr) => {
        static $name: $crate::sync::LazyLock<$type> = {
            let ptr = &raw const $name;
            let fn_ = $fn;
            unsafe { $crate::sync::LazyLock::init(ptr, fn_) }
        };
    };
}