Struct InstancePerThread

Source
pub struct InstancePerThread<T>
where T: Object,
{ /* private fields */ }
Expand description

A wrapper that manages linked instances of T, ensuring that only one instance of T is created per thread.

This is similar to the linked::thread_local_rc! macro, with the main difference being that this type operates entirely at runtime using dynamic storage and does not require a static variable to be defined.

§Usage

Create an instance of InstancePerThread and provide it the initial instance of a linked object T. Any instance of T accessed through the same InstancePerThread or a clone of it will be linked to the same family.

graph TD
    subgraph Thread1[Thread 1]
        Task1a[Local task] -->|"::acquire()"| Local1a[Ref]
        Task1b[Local task] -->|"::acquire()"| Local1b[Ref]

        Local1a --> SharedOwnership((Shared
ownership)) Local1b --> SharedOwnership SharedOwnership --> Instance1[Linked object instance] end subgraph Thread2[Thread 2] Task2a[Local task] -->|"::acquire()"| Local2a[Ref] Task2b[Local task] -->|"::acquire()"| Local2b[Ref] Local2a --> SharedOwnership2((Shared
ownership)) Local2b --> SharedOwnership2 SharedOwnership2 --> Instance2[Linked object instance] end Instance1 --> SharedState[Family state] Instance2 --> SharedState

To access the current thread’s instance of T, you must first obtain a Ref<T> by calling .acquire(). Then you can access the T within by simply dereferencing via the Deref<Target = T> trait.

Ref<T> is a thread-isolated type, meaning you cannot move it to a different thread nor access it from a different thread. To access linked instances on other threads, you must transfer the InstancePerThread<T> instance across threads and obtain a new Ref<T> on the destination thread.

§Resource management

A thread-specific instance of T is dropped when the last Ref on that thread is dropped, similar to how Rc<T> would behave. If a new Ref is later obtained, it is initialized with a new instance of the linked object.

It is important to emphasize that this means if you only acquire temporary Ref objects then you will get a new instance of T every time. The performance impact of this depends on how T works internally but you are recommended to keep Ref instances around for reuse when possible.

§Ref storage

Ref is a thread-isolated type, which means you cannot store it in places that require types to be thread-mobile. For example, in web framework request handlers the compiler might not permit you to let a Ref live across an await, depending on the web framework, the async task runtime used and its specific configuration.

Consider using InstancePerThreadSync<T> if you need a thread-mobile variant of Ref.

Implementations§

Source§

impl<T> InstancePerThread<T>
where T: Object,

Source

pub fn new(inner: T) -> Self

Creates a new InstancePerThread with an existing instance of T.

Any further access of T instances via the InstancePerThread (or its clones) will return instances of T from the same family.

Source

pub fn acquire(&self) -> Ref<T>

Returns a Ref<T> that can be used to access the current thread’s instance of T.

Creating multiple concurrent Ref<T> instances from the same InstancePerThread<T> on the same thread is allowed. Every Ref<T> instance will reference the same instance of T per thread.

There are no constraints on the lifetime of the returned Ref<T> but it is a thread-isolated type and cannot be moved across threads or accessed from a different thread, which may impose some limits.

§Example
use linked::InstancePerThread;

let linked_thing = InstancePerThread::new(Thing::new());

let thing = linked_thing.acquire();
thing.increment();
assert_eq!(thing.local_value(), 1);
§Efficiency

Reuse the returned Ref<T> when possible. Every call to this function has some overhead, especially if there are no other Ref<T> instances from the same family active on the current thread.

§Instance lifecycle

A thread-specific instance of T is dropped when the last Ref on that thread is dropped. If a new Ref is later obtained, it is initialized with a new linked instance of T linked to the same family as the originating InstancePerThread<T>.

use linked::InstancePerThread;

let linked_thing = InstancePerThread::new(Thing::new());

let thing = linked_thing.acquire();
thing.increment();
assert_eq!(thing.local_value(), 1);

drop(thing);

// Dropping the only acquired instance above will have reset the thread-local state.
let thing = linked_thing.acquire();
assert_eq!(thing.local_value(), 0);

To minimize the effort spent on re-creating the thread-local state, ensure that you reuse the Ref<T> instances as much as possible.

§Thread safety

The returned value is single-threaded and cannot be moved or used across threads. To extend the linked object family across threads, transfer InstancePerThread<T> instances across threads. You can obtain additional InstancePerThread<T> instances by cloning the original. Every clone is equivalent.

Trait Implementations§

Source§

impl<T> Clone for InstancePerThread<T>
where T: Object,

Source§

fn clone(&self) -> Self

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

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

Performs copy-assignment from source. Read more
Source§

impl<T> Debug for InstancePerThread<T>
where T: Object + Debug,

Source§

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

Formats the value using the given formatter. Read more

Auto Trait Implementations§

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.