Giter Club home page Giter Club logo

generic_singleton's People

Contributors

chaoses-ib avatar skifire13 avatar waltersmuts avatar

Stargazers

 avatar  avatar

Watchers

 avatar

generic_singleton's Issues

Does calling the macro from two different functions create two different objects?

I was experimenting with this crate and came across behavior that I did not expect, but I am not sure, if this is a bug or if my expectation was wrong.

The way I understood it from the documentation, the first time I call the macro get_or_init with a specific type, a singleton is created. This seems to work fine, when dealing with a single function, like in the example. But consider the following simple code example, where I attempt to have a generic registry singleton (just a hash map):

use std::collections::HashMap;
use std::fmt::Display;
use std::hash::Hash;
use std::sync::RwLock;

use generic_singleton::get_or_init;


fn add_to_registry<T>(key: T, value: T) -> bool
where
    T: Eq + Copy + Display + Hash + Send + Sync + 'static,
{
    let registry = get_or_init!(|| RwLock::new(HashMap::<T, T>::new()));
    if registry.read().unwrap().contains_key(&key) {
        false
    } else {
        registry.write().unwrap().insert(key, value);
        true
    }
}

fn get_from_registry<T>(key: T) -> T
where
    T: Eq + Copy + Display + Hash + Send + Sync + 'static,
{
    let registry = get_or_init!(|| RwLock::new(HashMap::<T, T>::new()));
    if !registry.read().unwrap().contains_key(&key) {
        panic!("No such key registered: {}", key)
    }
    *registry.read().unwrap().get(&key).unwrap()
}

fn main() {
    assert!(add_to_registry::<u32>(1, 10));
    assert!(!add_to_registry::<u32>(1, 20));
    let val = get_from_registry::<u32>(1);
    assert_eq!(val, 10);
}

The get_from_registry call causes a panic with No such key registered: 1.

I expected it to return the value 10 since the type involved is the exact same: The underlying data structure is a HashMap<u32, u32>, so I thought the macro would get me the same singleton that I successfully created in the first add_to_registry call. Apparently that is not the case.

Am I misunderstanding something? If so, how would I have to approach this, if I wanted such a generic "registry"-like singleton?

Data Race Unsoundness

The following code results in a bug from miri:

use std::{cell::RefCell, ops::AddAssign};

use num_traits::{One, Zero};

fn generic_call_counter<T: Zero + One + Copy + AddAssign + 'static>() -> T {
    let mut count = generic_singleton::get_or_init!(|| RefCell::new(T::zero())).borrow_mut();
    *count += T::one();
    *count
}

fn main() {
    let mut handles = Vec::new();
    for _ in 0..2 {
        handles.push(std::thread::spawn(|| {
            println!("{}", generic_call_counter::<i32>())
        }));
    }
    for handle in handles {
        handle.join().unwrap();
    }
}

BUG:

[walter@cuddles generic_singleton_user]$ cargo miri run
Preparing a sysroot for Miri (target: x86_64-unknown-linux-gnu)... done
    Finished dev [unoptimized + debuginfo] target(s) in 0.01s
     Running `/home/walter/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/cargo-miri runner target/miri/x86_64-unknown-linux-gnu/debug/generic_singleton_user`
1
error: Undefined Behavior: Data race detected between Read on thread `<unnamed>` and Write on thread `<unnamed>` at alloc3852
   --> /home/walter/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/cell.rs:452:18
    |
452 |         unsafe { *self.value.get() }
    |                  ^^^^^^^^^^^^^^^^^ Data race detected between Read on thread `<unnamed>` and Write on thread `<unnamed>` at alloc3852
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
    = note: BACKTRACE:
    = note: inside `std::cell::Cell::<isize>::get` at /home/walter/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/cell.rs:452:18
    = note: inside `std::cell::BorrowRefMut::<'_>::new` at /home/walter/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/cell.rs:1682:15
    = note: inside `std::cell::RefCell::<i32>::try_borrow_mut` at /home/walter/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/cell.rs:987:15
note: inside `generic_call_counter::<i32>` at src/main.rs:6:21
   --> src/main.rs:6:21
    |
6   |     let mut count = generic_singleton::get_or_init!(|| RefCell::new(T::zero())).borrow_mut();
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside closure at src/main.rs:15:28
   --> src/main.rs:15:28
    |
15  |             println!("{}", generic_call_counter::<i32>())
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

error: aborting due to previous error

The bug makes sense. Not sure why generic_singleton allows this usage :/

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.