StaticInstancePerThreadSync

Struct StaticInstancePerThreadSync 

Source
pub struct StaticInstancePerThreadSync<T>
where T: Object + Send + Sync,
{ /* private fields */ }
Expand description

This is the real type of variables wrapped in the linked::thread_local_arc! macro. See macro documentation for more details.

Instances of this type are created by the linked::thread_local_arc! macro, never directly by user code, which can call .with() or .to_arc() to work with or obtain a linked instance of T.

Implementations§

Source§

impl<T> StaticInstancePerThreadSync<T>
where T: Object + Send + Sync,

Source

pub fn with<F, R>(&self, f: F) -> R
where F: FnOnce(&Arc<T>) -> R,

Executes a closure with the current thread’s linked instance from the object family referenced by the static variable.

§Example
use std::thread;

linked::thread_local_arc!(static METRICS: MetricsCollector = MetricsCollector::new());

// Use .with() for efficient access when you do not need to store the Arc
METRICS.with(|metrics| {
    metrics.record_request();
    assert_eq!(metrics.local_count(), 1);
    assert_eq!(metrics.global_count(), 1);
});

// Multiple calls to .with() access the same thread-local instance
METRICS.with(|metrics| {
    assert_eq!(metrics.local_count(), 1); // Still 1 from previous call
    assert_eq!(metrics.global_count(), 1); // Still 1 globally
});

// Each thread gets its own instance with fresh local state but shared global state
thread::spawn(|| {
    METRICS.with(|metrics| {
        assert_eq!(metrics.local_count(), 0); // Fresh local count for this thread
        assert_eq!(metrics.global_count(), 1); // But sees global count from main thread
         
        metrics.record_request();
        assert_eq!(metrics.local_count(), 1); // Local count incremented
        assert_eq!(metrics.global_count(), 2); // Global count now 2
    });
}).join().unwrap();

// Back on main thread: local state unchanged, global state updated
METRICS.with(|metrics| {
    assert_eq!(metrics.local_count(), 1); // Still 1 locally
    assert_eq!(metrics.global_count(), 2); // But sees update from other thread
});
§Performance

For repeated access to the current thread’s linked instance, prefer reusing an Arc<T> obtained from .to_arc().

If your code is not in a situation where it can reuse an existing Arc<T>, this method is the optimal way to access the current thread’s linked instance of T.

Source

pub fn to_arc(&self) -> Arc<T>

Gets an Arc<T> to the current thread’s linked instance from the object family referenced by the static variable.

The instance behind this Arc is the same one accessed by all other calls through the static variable on this thread. Note that it is still possible to create multiple instances on a single thread, e.g. by cloning the T within. The “one instance per thread” logic only applies when the instances are accessed through the static variable.

§Example
use std::thread;

linked::thread_local_arc!(static MONITOR: ServiceMonitor = ServiceMonitor::new());

// Get an Arc to reuse across multiple operations
let monitor = MONITOR.to_arc();
monitor.check_service(true);
monitor.check_service(false); // This will increment global failures
assert_eq!(monitor.local_checks(), 2);
assert_eq!(monitor.global_failures(), 1);

// Multiple calls to to_arc() return Arc to the same instance
let monitor2 = MONITOR.to_arc();
assert_eq!(monitor2.local_checks(), 2); // Same instance as monitor
assert_eq!(monitor2.global_failures(), 1);

// Clone the Arc for efficiency when passing around
let monitor_clone = Arc::clone(&monitor);
monitor_clone.check_service(true);
assert_eq!(monitor.local_checks(), 3);
assert_eq!(monitor.global_failures(), 1);

// You can send the Arc to other threads (since T: Send + Sync)
let monitor_for_thread = Arc::clone(&monitor);
thread::spawn(move || {
    // This Arc still refers to the original thread's instance
    monitor_for_thread.check_service(false);
}).join().unwrap();
assert_eq!(monitor.local_checks(), 4); // Local checks on main thread: 4
assert_eq!(monitor.global_failures(), 2); // Global failures from both threads: 2

// But each thread gets its own instance when accessing through the static
thread::spawn(|| {
    let thread_monitor = MONITOR.to_arc();
    assert_eq!(thread_monitor.local_checks(), 0); // Fresh local state
    assert_eq!(thread_monitor.global_failures(), 2); // But sees shared global state
     
    thread_monitor.check_service(false);
    assert_eq!(thread_monitor.local_checks(), 1); // Local: 1
    assert_eq!(thread_monitor.global_failures(), 3); // Global: 3
}).join().unwrap();

// Back on main thread: local state unchanged, global state updated
assert_eq!(monitor.local_checks(), 4); // Still 4 locally
assert_eq!(monitor.global_failures(), 3); // But sees update from other thread
§Performance

This function merely clones an Arc, which is relatively fast but still more work than doing nothing. The most efficient way to access the current thread’s linked instance is to reuse the Arc<T> returned from this method.

If you are not in a situation where you can reuse the Arc<T> and a shared reference is satisfactory, prefer calling .with() instead, which does not create an Arc and thereby saves a few nanoseconds.

Trait Implementations§

Source§

impl<T> Debug for StaticInstancePerThreadSync<T>
where T: Object + Send + Sync + 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> 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.