async_named_locker/
named_state.rs

1use std::collections::{HashMap};
2use std::hash::Hash;
3use std::sync::{Arc, Mutex, Weak};
4use std::time::{SystemTime, UNIX_EPOCH};
5
6pub struct NamedStateGuard<N: Hash + Eq + PartialEq + Clone> {
7    holder: Weak<NamedStateHolder<N>>,
8    name: N,
9    id: u64,
10}
11
12impl<N: Hash + Eq + PartialEq + Clone> Drop for NamedStateGuard<N> {
13    fn drop(&mut self) {
14        if let Some(holder) = self.holder.upgrade() {
15            holder.release_state(self.name.clone(), self.id);
16        }
17    }
18}
19
20struct State<N: Hash + Eq + PartialEq + Clone> {
21    names: HashMap<N, Vec<u64>>,
22    id_seq: u64,
23}
24pub struct NamedStateHolder<N: Hash + Eq + PartialEq + Clone> {
25    state: Mutex<State<N>>
26}
27
28impl <N: Hash + Eq + PartialEq + Clone> NamedStateHolder<N> {
29    pub fn new() -> Arc<Self> {
30        Arc::new(Self {
31            state: Mutex::new(State {
32                names: HashMap::new(),
33                id_seq: SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_millis() as u64,
34            })
35        })
36    }
37
38    pub fn new_state(self: &Arc<Self>, name: N) -> NamedStateGuard<N> {
39        let mut state = self.state.lock().unwrap();
40        let id = state.id_seq;
41        state.id_seq += 1;
42        let list = state.names.entry(name.clone()).or_insert(vec![]);
43        list.push(id);
44        NamedStateGuard {
45            holder: Arc::downgrade(self),
46            name,
47            id,
48        }
49    }
50
51    pub fn has_state(&self, name: N) -> bool {
52        let state = self.state.lock().unwrap();
53        if let Some(list) = state.names.get(&name) {
54            list.len() > 0
55        } else {
56            false
57        }
58    }
59
60    pub(crate) fn release_state(self: &Arc<Self>, name: N, id: u64) {
61        let mut state = self.state.lock().unwrap();
62        let list = state.names.entry(name.clone()).or_insert(vec![]);
63        list.retain(|&x| x != id);
64    }
65}
66
67#[cfg(test)]
68mod test {
69    use crate::NamedStateHolder;
70
71    #[tokio::test]
72    async fn test() {
73        let holder = NamedStateHolder::new();
74
75        let holder1 = holder.clone();
76        let handle = tokio::spawn(async move {
77            let _guard1 = holder1.new_state("test".to_string());
78            tokio::time::sleep(std::time::Duration::from_secs(2)).await;
79        });
80        tokio::time::sleep(std::time::Duration::from_secs(1)).await;
81        assert!(holder.has_state("test".to_string()));
82        handle.await.unwrap();
83        assert!(!holder.has_state("test".to_string()));
84
85        let holder1 = holder.clone();
86        let handle = tokio::spawn(async move {
87            let _guard1 = holder1.new_state("test".to_string());
88            tokio::time::sleep(std::time::Duration::from_secs(2)).await;
89        });
90
91        let holder1 = holder.clone();
92        let handle2 = tokio::spawn(async move {
93            let _guard1 = holder1.new_state("test".to_string());
94            tokio::time::sleep(std::time::Duration::from_secs(5)).await;
95        });
96        tokio::time::sleep(std::time::Duration::from_secs(1)).await;
97
98        assert!(holder.has_state("test".to_string()));
99        handle.await.unwrap();
100        assert!(holder.has_state("test".to_string()));
101        handle2.await.unwrap();
102        assert!(!holder.has_state("test".to_string()));
103    }
104}