Struct global_counter::generic::Counter[][src]

pub struct Counter<T: Inc>(_);

A generic, gobal counter.

This counter holds up rusts guarantees of freedom of data-races. Any caveats are clearly pointed out in the documentation.

This counter is implemented using a Mutex, which can be slow if a lot of contention is involved. To circumvent this, consider extracting the ‘counted parts’ of your struct into primitives, which can then be counted by much faster primitive counters. Abstracting can then restore the original interface.

Avoid premature optimzation though!

Implementations

impl<T: Inc> Counter<T>[src]

pub fn new(val: T) -> Counter<T>[src]

Creates a new generic counter.

This function is not const yet. As soon as Mutex::new() is stable as const fn, this will be as well, if the parking_lot feature is not disabled. Then, the exported macros will no longer be needed.

pub fn get_borrowed(&self) -> impl Deref<Target = T> + '_[src]

Returns (basically) an immutable borrow of the underlying value. Best make sure this borrow goes out of scope before any other methods of the counter are being called.

If T is not Clone, this is the only way to access the current value of the counter.

Warning: Attempting to access the counter from the thread holding this borrow will result in a deadlock or panic. This is usual mutex behaviour. As long as this borrow is alive, no accesses to the counter from any thread are possible.

Good Example - Borrow goes out of scope

fn main(){
    global_default_counter!(COUNTER, u8);
    assert_eq!(0, *COUNTER.get_borrowed());

    // The borrow is already out of scope, we can call inc safely.
    COUNTER.inc();

    assert_eq!(1, *COUNTER.get_borrowed());}

Good Example - At most one concurrent access per thread

fn main(){
    global_default_counter!(COUNTER, u8);
    assert_eq!(0, *COUNTER.get_borrowed());
     
    // Using this code, there is no danger of data races, race coditions whatsoever.
    // As at each point in time, each thread either has a borrow of the counters value alive,
    // or is accessing the counter using its api, never both at the same time.
    let t1 = std::thread::spawn(move || {
        COUNTER.inc();
        let value_borrowed = COUNTER.get_borrowed();
        assert!(1 <= *value_borrowed, *value_borrowed <= 3);
    });
    let t2 = std::thread::spawn(move || {
        COUNTER.inc();
        let value_borrowed = COUNTER.get_borrowed();
        assert!(1 <= *value_borrowed, *value_borrowed <= 3);
    });
    let t3 = std::thread::spawn(move || {
        COUNTER.inc();
        let value_borrowed = COUNTER.get_borrowed();
        assert!(1 <= *value_borrowed, *value_borrowed <= 3);
    });

    t1.join().unwrap();
    t2.join().unwrap();
    t3.join().unwrap();
     
    assert_eq!(3, *COUNTER.get_borrowed());}

Bad Example

// We spawn a new thread. This thread will try lockig the counter twice, causing a deadlock.
std::thread::spawn(move || {

    // We could also use get_cloned with this counter, circumventing all these troubles.
    global_default_counter!(COUNTER, u32);
     
    // The borrow is now alive, and this thread now holds a lock onto the counter.
    let counter_value_borrowed = COUNTER.get_borrowed();
    assert_eq!(0, *counter_value_borrowed);

    // Now we try to lock the counter again, but we already hold a lock in the current thread! Deadlock!
    COUNTER.inc();
     
    // Here we use `counter_value_borrowed` again, ensuring it can't be dropped "fortunately".
    // This line will never actually be reached.
    assert_eq!(0, *counter_value_borrowed);
});

pub fn get_mut_borrowed(&self) -> impl DerefMut<Target = T> + '_[src]

Returns a mutable borrow of the counted value, meaning the actual value counted by this counter can be mutated through this borrow.

The constraints pointed out for get_borrowed also apply here.

Although this API is in theory as safe as its immutable equivalent, usage of it is discouraged, as it is highly unidiomatic.

pub fn set(&self, val: T)[src]

Sets the counted value to the given value.

pub fn inc(&self)[src]

Increments the counter, delegating the specific implementation to the Inc trait.

impl<T: Inc + Clone> Counter<T>[src]

pub fn get_cloned(&self) -> T[src]

This avoid the troubles of get_borrowed by cloning the current value.

Creating a deadlock using this API should be impossible, it might however violate implicit synchronization assumptions.

pub fn inc_cloning(&self) -> T[src]

Increments the counter, returning the previous value, cloned.

impl<T: Inc + Default> Counter<T>[src]

pub fn reset(&self)[src]

Resets the counter to its default value.

Trait Implementations

impl<T: Debug + Inc> Debug for Counter<T>[src]

impl<T: Default + Inc> Default for Counter<T>[src]

Auto Trait Implementations

impl<T> RefUnwindSafe for Counter<T>

impl<T> Send for Counter<T> where
    T: Send

impl<T> Sync for Counter<T> where
    T: Send

impl<T> Unpin for Counter<T> where
    T: Unpin

impl<T> UnwindSafe for Counter<T>

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

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

The type returned in the event of a conversion error.