Struct Lazy

Source
pub struct Lazy<T> { /* private fields */ }
Expand description

We want to have a static value that’s set at runtime and this executor will only use libstd. As of 10/26/21, the lazy types in std are still only on nightly and we can’t use another crate, so crates like once_cell and lazy_static are also out. Thus, we create our own Lazy type so that it will calculate the value only once and only when we need it.

Implementations§

Source§

impl<T> Lazy<T>

Source

pub const fn new() -> Self

We must construct the type using a const fn so that it can be used in static contexts. The nice thing is that all of the function calls we make here are also const and so this will just work. The compiler will figure it all out and make sure the Lazy static value exists in our final binary.

Source

pub fn get_or_init(&self, func: fn() -> T) -> &T

This function will either grab a reference to the type or creates it with a given function

Trait Implementations§

Source§

impl<T> Drop for Lazy<T>

We now need to implement Drop by hand specifically because MaybeUninit will need us to drop the value it holds by ourselves only if it exists. We check if the value exists, swap it out with an uninitialized value and then change MaybeUninit<T> into just a T with a call to assume_init and then call drop on T itself

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

impl<T: Send> Send for Lazy<T>

Now you might be asking yourself why we are implementing these traits by hand and also why it’s unsafe to do so. UnsafeCellis the big reason here and you can see this by commenting these two lines and trying to compile the code. Because of how auto traits work then if any part is not Send and Sync then we can’t use Lazy for a static. Note that auto traits are a compiler specific thing where if everything in a type implements a trait then that type also implements it. Send and Sync are great examples of this where any type becomes Send and/or Sync if all its types implement them too! UnsafeCell specifically implements !Sync and since it is not Sync then it can’t be used in a static. We can override this behavior though by implementing these traits for Lazy here though. We’re saying that this is okay and that we uphold the invariants to be Send + Sync. We restrict it though and say that this is only the case if the type T inside Lazy is Sync only if T is Send + Sync. We know then that this is okay because the type in UnsafeCell can be safely referenced through an &'static and that the type it holds is also safe to use across threads. This means we can set Lazy as Send + Sync even though the internal UnsafeCell is !Sync in a safe way since we upheld the invariants for these traits.

Source§

impl<T: Send + Sync> Sync for Lazy<T>

Auto Trait Implementations§

§

impl<T> !Freeze for Lazy<T>

§

impl<T> !RefUnwindSafe for Lazy<T>

§

impl<T> Unpin for Lazy<T>
where T: Unpin,

§

impl<T> UnwindSafe for Lazy<T>
where T: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.