async_named_locker/
named_state.rs1use 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}