Struct Elastic

Source
pub struct Elastic<T: Stretched> { /* private fields */ }
Expand description

A container for a stretched value.

This acts a bit like Arc<AtomicRefCell<Option<T>>>, through its Clone behavior and borrowing methods, but the similarity ends there. The only way to put data into this type is through Elastic::loan, which allows you to safely loan some Stretchable, non-'static type, to an Elastic carrying the corresponding Stretched type. As Stretched requires 'static, Elastic<T> is always 'static and can be used to access non-'static types safely from contexts which require 'static (such as dynamic typing with Any or the hv-alchemy crate.) The lifetime is preserved by a scope guard, ElasticGuard, which is provided when a value is loaned and which revokes the loan when it is dropped or has the loaned value forcibly taken back by ElasticGuard::take. In most cases, you won’t actually see these ElasticGuards as they’ll be created and stashed away by a ScopeGuard, which you should be using to perform all your loans.

Elastic<T> is thread-safe. However, internally, it uses an AtomicRefCell, so if you violate borrowing invariants, you will have a panic on your hands. This goes likewise for taking the value back w/ ElasticGuard or dropping the guard: the guard will panic if it cannot take back the value.

§Soundness

As long as you fulfill its requirements with respect to its guards, Elastic is sound in all normal modes of operation. However, in the case of a panic across threads, bad things can happen:

  • If an elastic exists on one thread and is being loaned to with a guard on another thread, and the thread holding the guard panicks, it is unclear what will/should happen to the other thread. Most likely, the thread holding the guard will attempt to drop the guard, which will then cause the guard’s Drop impl to panic, which will then cause an abort (as panicking during a panick will cause an abort.) However, if the panic starts in the guard’s Drop impl, and the guard is handling a reference which has been loaned to it, it is possible that the original owner of the data being borrowed there could be dropped, while the other thread is holding an open borrow on a reference to that data. Since this lib is no_std, we cannot std::process::abort(). We may be able to consider this soundness hole plugged by marking this type !UnwindSafe or requiring that stretched types be UnwindSafe; this is an open question.

So in short, unless you’re worried about recovering from panicks across threads where the thread panicking is the one that originally owned the data (and most likely the parent thread), Elastic is thought to be completely sound.

Implementations§

Source§

impl<T: Stretched> Elastic<T>

Source

pub fn new() -> Self

Create an empty Elastic<T>.

Source

pub fn borrow<'a>( &'a self, ) -> AtomicRef<'a, <T::Parameterized<'a> as Deref>::Target>
where T::Parameterized<'a>: Deref,

Immutably borrow the loaned value. Panicks if the elastic is already mutably borrowed or if it was never loaned to/any loans have expired.

This method assumes that the stretchable type is a reference or smart pointer and can be immediately dereferenced; if that’s not the case, please use try_borrow_as_parameterized.

Source

pub fn borrow_mut<'a>( &'a self, ) -> AtomicRefMut<'a, <T::Parameterized<'a> as Deref>::Target>
where T::Parameterized<'a>: DerefMut,

Mutably borrow the loaned value. Panicks if the elastic is already borrowed or if it was never loaned to/any loans have expired.

This method assumes that the stretchable type is a reference or smart pointer and can be immediately dereferenced; if that’s not the case, please use try_borrow_as_parameterized_mut.

Source

pub fn borrow_arc<'a>( &'a self, ) -> ArcRef<<T::Parameterized<'a> as Deref>::Target, Option<T>>
where T::Parameterized<'a>: Deref,

Immutably borrow the loaned value through a reference-counted guard. Panicks if the elastic is already mutably borrowed or if it was never loaned to/any loans have expired.

This method assumes that the stretchable type is a reference or smart pointer and can be immediately dereferenced; if that’s not the case, please use try_borrow_as_parameterized_arc.

Source

pub fn borrow_arc_mut<'a>( &'a self, ) -> ArcRefMut<<T::Parameterized<'a> as Deref>::Target, Option<T>>
where T::Parameterized<'a>: DerefMut,

Mutably borrow the loaned value through a reference-counted guard. Panicks if the elastic is already borrowed or if it was never loaned to/any loans have expired.

This method assumes that the stretchable type is a reference or smart pointer and can be immediately dereferenced; if that’s not the case, please use try_borrow_as_parameterized_arc_mut.

Source

pub fn try_borrow<'a>( &'a self, ) -> Result<AtomicRef<'a, <T::Parameterized<'a> as Deref>::Target>, BorrowError>
where T::Parameterized<'a>: Deref,

Immutably borrow the loaned value. Returns Err if the elastic is already mutably borrowed or if it was never loaned to/any loans have expired.

This method assumes that the stretchable type is a reference or smart pointer and can be immediately dereferenced; if that’s not the case, please use try_borrow_as_parameterized.

Source

pub fn try_borrow_arc<'a>( &'a self, ) -> Result<ArcRef<<T::Parameterized<'a> as Deref>::Target, Option<T>>, BorrowError>
where T::Parameterized<'a>: Deref,

Immutably borrow the loaned value through a reference-counted guard. Returns Err if the elastic is already mutably borrowed or if it was never loaned to/any loans have expired.

This method assumes that the stretchable type is a reference or smart pointer and can be immediately dereferenced; if that’s not the case, please use try_borrow_as_parameterized_arc.

Source

pub fn try_borrow_arc_mut<'a>( &'a self, ) -> Result<ArcRefMut<<T::Parameterized<'a> as Deref>::Target, Option<T>>, BorrowMutError>
where T::Parameterized<'a>: DerefMut,

Mutably borrow the loaned value through a reference-counted guard. Returns Err if the elastic is already borrowed or if it was never loaned to/any loans have expired.

This method assumes that the stretchable type is a reference or smart pointer and can be immediately dereferenced; if that’s not the case, please use try_borrow_as_parameterized_arc_mut.

Source

pub fn try_borrow_mut<'a>( &'a self, ) -> Result<AtomicRefMut<'a, <T::Parameterized<'a> as Deref>::Target>, BorrowMutError>
where T::Parameterized<'a>: DerefMut,

Mutably borrow the loaned value. Returns Err if the elastic is already borrowed or if it was never loaned to/any loans have expired.

This method assumes that the stretchable type is a refence or smart pointer and can be immediately dereferenced; if that’s not the case, please use try_borrow_as_parameterized_mut.

Source

pub fn try_borrow_as_parameterized( &self, ) -> Result<AtomicRef<'_, T::Parameterized<'_>>, BorrowError>

Attempt to immutably borrow the loaned value, if present.

Source

pub fn try_borrow_as_parameterized_mut( &self, ) -> Result<AtomicRefMut<'_, T::Parameterized<'_>>, BorrowMutError>

Attempt to mutably borrow the loaned value, if present.

Source

pub fn try_borrow_as_parameterized_arc( &self, ) -> Result<ArcRef<T::Parameterized<'_>, Option<T>>, BorrowError>

Attempt to immutably borrow the loaned value, via a reference-counted guard.

Source

pub fn try_borrow_as_parameterized_arc_mut( &self, ) -> Result<ArcRefMut<T::Parameterized<'_>, Option<T>>, BorrowMutError>

Attempt to mutably borrow the loaned value, via a reference-counted guard..

Source

pub unsafe fn loan<'a>( &self, t: T::Parameterized<'a>, ) -> ElasticGuard<'a, T::Parameterized<'a>>

Loan a stretchable value to this Elastic in exchange for a guard object which ends the loan when the value is taken back or when the guard is dropped.

Panics if there is already a loan in progress to this Elastic.

§Safety

The guard must have its destructor run by the end of its lifetime, either by dropping it or using ElasticGuard::take. Calling core::mem::forget on an ElasticGuard is considered instant undefined behavior, as it leaves an Elastic in a state which is not well-defined and potentially contains a stretched value which is long past the end of its life, causing a use-after-free.

Trait Implementations§

Source§

impl<T: Stretched> Clone for Elastic<T>

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<T: Stretched> Debug for Elastic<T>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<T: Stretched> Default for Elastic<T>

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl<T: Stretched, U: ?Sized> NonBlockingGuardedBorrow<U> for Elastic<T>
where for<'a> T::Parameterized<'a>: Borrow<U>,

Source§

type Guard<'a> = AtomicRef<'a, U> where U: 'a

The guard type (for example, std::cell::Ref<'a, T>.)
Source§

type BorrowError<'a> = BorrowError where U: 'a

The type returned in the case the value cannot be borrowed.
Source§

fn try_nonblocking_guarded_borrow( &self, ) -> Result<Self::Guard<'_>, Self::BorrowError<'_>>

Attempt to perform the borrow.
Source§

impl<T: Stretched, U: ?Sized> NonBlockingGuardedBorrowMut<U> for Elastic<T>
where for<'a> T::Parameterized<'a>: BorrowMut<U>,

Source§

type GuardMut<'a> = AtomicRefMut<'a, U> where U: 'a

The guard type (for example, std::cell::RefMut<'a, T>.)
Source§

type BorrowMutError<'a> = BorrowMutError where U: 'a

The type returned in the case the value cannot be borrowed.
Source§

fn try_nonblocking_guarded_borrow_mut( &self, ) -> Result<Self::GuardMut<'_>, Self::BorrowMutError<'_>>

Attempt to perform the borrow.
Source§

impl<T: Stretched, U: ?Sized> NonBlockingGuardedMutBorrowMut<U> for Elastic<T>
where for<'a> T::Parameterized<'a>: BorrowMut<U>,

Source§

type MutGuardMut<'a> = AtomicRefMut<'a, U> where U: 'a

The guard type (for example, std::sync::RwLockWriteGuard<'a, T>.)
Source§

type MutBorrowMutError<'a> = BorrowMutError where U: 'a

The type returned in the case the value cannot be borrowed.
Source§

fn try_nonblocking_guarded_mut_borrow_mut( &mut self, ) -> Result<Self::MutGuardMut<'_>, Self::MutBorrowMutError<'_>>

Attempt to perform the borrow.

Auto Trait Implementations§

§

impl<T> Freeze for Elastic<T>

§

impl<T> !RefUnwindSafe for Elastic<T>

§

impl<T> Send for Elastic<T>
where T: Send + Sync,

§

impl<T> Sync for Elastic<T>
where T: Send + Sync,

§

impl<T> Unpin for Elastic<T>

§

impl<T> !UnwindSafe for Elastic<T>

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> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. 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> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
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.