rt 0.19.0

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

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

pub struct OnceLock<T> {
    once: Once,
    value: UnsafeCell<MaybeUninit<T>>,
}

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

    #[inline]
    pub fn get(&self) -> Option<&T> {
        if self.is_initialized() {
            Some(unsafe { self.get_unchecked() })
        } else {
            None
        }
    }

    #[inline]
    pub fn get_mut(&mut self) -> Option<&mut T> {
        if self.is_initialized() {
            Some(unsafe { self.get_unchecked_mut() })
        } else {
            None
        }
    }

    #[inline]
    pub fn set(&self, value: T) -> Result<(), T> {
        let mut value = Some(value);
        self.initialize(|| unsafe { value.take().unwrap_unchecked() });
        value.map_or(Ok(()), Err)
    }

    #[inline]
    pub fn get_or_init<F>(&self, f: F) -> &T
    where
        F: FnOnce() -> T,
    {
        self.initialize(f);
        unsafe { self.get_unchecked() }
    }

    #[inline]
    pub fn get_mut_or_init<F>(&mut self, f: F) -> &mut T
    where
        F: FnOnce() -> T,
    {
        self.initialize(f);
        unsafe { self.get_unchecked_mut() }
    }

    #[inline]
    fn is_initialized(&self) -> bool {
        self.once.is_completed()
    }

    #[cold]
    fn initialize<F>(&self, f: F)
    where
        F: FnOnce() -> T,
    {
        self.once.call_once(|| unsafe {
            (*self.value.get()).write(f());
        });
    }

    #[inline]
    unsafe fn get_unchecked(&self) -> &T {
        debug_assert!(self.is_initialized());
        unsafe { (*self.value.get()).assume_init_ref() }
    }

    #[inline]
    unsafe fn get_unchecked_mut(&mut self) -> &mut T {
        debug_assert!(self.is_initialized());
        unsafe { (*self.value.get()).assume_init_mut() }
    }
}

// Why do we need `T: Send`?
// Thread A creates a `OnceLock` and shares it with
// scoped thread B, which fills the cell, which is
// then destroyed by A. That is, destructor observes
// a sent value.
unsafe impl<T: Sync + Send> Sync for OnceLock<T> {}
unsafe impl<T: Send> Send for OnceLock<T> {}

impl<T: RefUnwindSafe + UnwindSafe> RefUnwindSafe for OnceLock<T> {}
impl<T: UnwindSafe> UnwindSafe for OnceLock<T> {}

impl<T: PartialEq> PartialEq for OnceLock<T> {
    #[inline]
    fn eq(&self, other: &OnceLock<T>) -> bool {
        self.get() == other.get()
    }
}

impl<T: Eq> Eq for OnceLock<T> {}

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