1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
//! # serial_test
//! Helper crate for [serial_test_derive](../serial_test_derive/index.html)

use lazy_static::lazy_static;
use std::collections::HashMap;
use std::ops::{Deref, DerefMut};
use std::sync::{Arc, Mutex, RwLock};

lazy_static! {
    static ref LOCKS: Arc<RwLock<HashMap<String, Mutex<()>>>> =
        Arc::new(RwLock::new(HashMap::new()));
}

/// Helper function for [serial_test_derive::serial](../serial_test_derive/attr.serial.html)
/// ```
/// #[test]
/// fn test_serial_core() {
///     serial_core("some key", || {
///         println!("Bar");
///     });
/// }
/// ```
pub fn serial_core(name: &str, function: fn()) {
    // Check if a new key is needed. Just need a read lock, which can be done in sync with everyone else
    let new_key = {
        let unlock = LOCKS.read().unwrap();
        !unlock.deref().contains_key(name)
    };
    if new_key {
        // This is the rare path, which avoids the multi-writer situation mostly
        LOCKS
            .write()
            .unwrap()
            .deref_mut()
            .insert(name.to_string(), Mutex::new(()));
    }
    let unlock = LOCKS.read().unwrap();
    // _guard needs to be named to avoid being instant dropped
    let _guard = unlock.deref()[name].lock();
    function();
}