JailCell

Struct JailCell 

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

Represents a single standalone value that allows interior mutability while upholding memory safety with a reference counting usize

This is a very simple implementation of the principles found in Prison

It has a single UnsafeCell to allow interior mutability. The UnsafeCell holds one single usize to track mutable and immutable references, and the value itself of type T

It has visit_ref(), visit_mut(), guard_ref(), and guard_mut() methods, just like Prison, but with drastically simpler requirements for safety checking.

§Example

let string_jail: JailCell<String> = JailCell::new(String::from("'Bad-Guy' Bert"));
string_jail.visit_mut(|criminal| {
    let bigger_bad = String::from("Dr. Lego-Step");
    println!("Breaking News: {} to be set free to make room for {}", *criminal, bigger_bad);
    *criminal = bigger_bad;
    Ok(())
})?;
let guarded_criminal = string_jail.guard_ref()?;
println!("{} will now be paraded around town for public shaming", *guarded_criminal);
assert_eq!(*guarded_criminal, String::from("Dr. Lego-Step"));
JailValueRef::unguard(guarded_criminal);

Implementations§

Source§

impl<T> JailCell<T>

Source

pub fn new(value: T) -> JailCell<T>

Creates a new JailCell with the supplied value of type T

After creation, mutable or immutable references to it’s value can only be obtained through its visit_*() or guard_*() methods

Source

pub fn visit_mut<F>(&self, operation: F) -> Result<(), AccessError>
where F: FnMut(&mut T) -> Result<(), AccessError>,

Obtain a mutable reference to the JailCell’s internal value that gets passed to a closure you provide.

§Example
let string_jail: JailCell<String> = JailCell::new(String::from("'Bad-Guy' Bert"));
string_jail.visit_mut(|criminal| {
    let bigger_bad = String::from("Dr. Lego-Step");
    println!("Breaking News: {} to be set free to make room for {}", *criminal, bigger_bad);
    *criminal = bigger_bad;
    Ok(())
})?;
§Errors
  • [AccessError::ValueAlreadyMutablyReferenced(0)] if value is already mutably referenced
  • [AccessError::ValueStillImmutablyReferenced(0)] if value has any number of immutable references
§Example
let jail: JailCell<u32> = JailCell::new(42);
jail.visit_mut(|val| {
    assert!(jail.visit_mut(|val| Ok(())).is_err());
    Ok(())
})?;
jail.visit_ref(|val| {
    assert!(jail.visit_mut(|val| Ok(())).is_err());
    Ok(())
})?;
Source

pub fn visit_ref<F>(&self, operation: F) -> Result<(), AccessError>
where F: FnMut(&T) -> Result<(), AccessError>,

Obtain an immutable reference to the JailCell’s internal value that gets passed to a closure you provide.

§Example
let string_jail: JailCell<String> = JailCell::new(String::from("'Bad-Guy' Bert"));
string_jail.visit_ref(|criminal| {
    println!("Breaking News: {} was just captured!", *criminal);
    Ok(())
})?;
§Errors
  • [AccessError::ValueAlreadyMutablyReferenced(0)] if value is already mutably referenced
  • [AccessError::MaximumImmutableReferencesReached(0)] if value has usize::MAX - 2 immutable references already
§Example
let jail: JailCell<u32> = JailCell::new(42);
jail.visit_mut(|val| {
    assert!(jail.visit_ref(|val| Ok(())).is_err());
    Ok(())
})?;
Source

pub fn guard_mut<'a>(&'a self) -> Result<JailValueMut<'a, T>, AccessError>

Obtain an JailValueMut that marks the JailCell mutably referenced as long as it remains in scope and automatically unlocks it when it falls out of scope

JailValueMut implements [Deref<Target = T>], [DerefMut<Target = T>], AsRef, AsMut, Borrow, and BorrowMut to allow transparent access to its underlying value

You may manually drop the JailValueMut out of scope by passing it to the function [JailValueMut::unguard(_jail_val_mut)]

§Example
let string_jail: JailCell<String> = JailCell::new(String::from("'Bad-Guy' Bert"));
let mut grd_criminal = string_jail.guard_mut()?;
let bigger_bad = String::from("Dr. Lego-Step");
println!("Breaking News: {} to be set free to make room for {}", *grd_criminal, bigger_bad);
*grd_criminal = bigger_bad;
JailValueMut::unguard(grd_criminal);
§Errors
  • [AccessError::ValueAlreadyMutablyReferenced(0)] if value is already mutably referenced
  • [AccessError::ValueStillImmutablyReferenced(0)] if value has any number of immutable references
§Example
let jail: JailCell<u32> = JailCell::new(42);
let guard_ref = jail.guard_ref()?;
assert!(jail.guard_mut().is_err());
JailValueRef::unguard(guard_ref);
let guard_mut = jail.guard_mut()?;
assert!(jail.guard_mut().is_err());
JailValueMut::unguard(guard_mut);
Source

pub fn guard_ref<'a>(&'a self) -> Result<JailValueRef<'a, T>, AccessError>

Obtain an JailValueRef that marks the JailCell mutably referenced as long as it remains in scope and automatically unlocks it when it falls out of scope

JailValueRef implements [Deref<Target = T>], AsRef, and Borrow to allow transparent access to its underlying value

You may manually drop the JailValueRef out of scope by passing it to the function [JailValueRef::unguard(_jail_val_ref)]

§Example
let string_jail: JailCell<String> = JailCell::new(String::from("'Bad-Guy' Bert"));
let grd_criminal = string_jail.guard_ref()?;
println!("Breaking News: {} has been captured!", *grd_criminal);
JailValueRef::unguard(grd_criminal);
§Errors
  • [AccessError::ValueAlreadyMutablyReferenced(0)] if value is already mutably referenced
  • [AccessError::MaximumImmutableReferencesReached(0)] if value has usize::MAX - 2 immutable references already
§Example
let jail: JailCell<u32> = JailCell::new(42);
let guard_mut = jail.guard_mut()?;
assert!(jail.guard_ref().is_err());
JailValueMut::unguard(guard_mut);
Source

pub fn clone_val(&self) -> T
where T: Clone,

Clones the requested value out of the JailCell into a new variable

Only available when type T implements Clone (it is assumed that the implementation of T::clone() is memory safe).

Because cloning does not alter the original, and because the new variable to hold the clone does not have any presumtions about the value, it is safe (in a single-threaded context) to clone out the value even if it is being visited or guarded.

§Example
let jail: JailCell<String> = JailCell::new(String::from("Dolly"));
let guard_mut = jail.guard_mut()?;
let dolly_2 = jail.clone_val();
JailValueMut::unguard(guard_mut);
assert_eq!(dolly_2, String::from("Dolly"));
Source

pub unsafe fn peek_ref<'a>(&'a self) -> &'a T

Get a reference to the value while ignoring reference counting and most other safety measures

This method is provided as a way for libraries depending on this code to perform niche optimized reads of contained values without the overhead of the normal safety checks, or when a mutable reference is active but you can statically confirm that the value will not be mutated from the begining of the returned &T’s lifetime to the end of it’s lifetime.

The returned reference is intended to be short-lived and safely contained in a scope where no mutation of the value takes place

§Safety

When you call this method and as long as the &T it returns remains in-scope/alive, you MUST ensure the following:

  • The value MUST NOT be mutated by ANY source, including active safe reference-counted mutable references
  • NO operation can be performed that could potentially cause the underlying memory address of the JailCell’s data to relocate

Trait Implementations§

Source§

impl<T> Default for JailCell<T>
where T: Default,

Source§

fn default() -> Self

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

Auto Trait Implementations§

§

impl<T> !Freeze for JailCell<T>

§

impl<T> !RefUnwindSafe for JailCell<T>

§

impl<T> Send for JailCell<T>
where T: Send,

§

impl<T> !Sync for JailCell<T>

§

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

§

impl<T> UnwindSafe for JailCell<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.