Newbie here. Just trying to implement an EventBox
which wraps CondVar to provide easy event handling object.
The code likes this:
use std::sync::{Condvar, Mutex};
use std::collections::HashMap;
use std::any::Any;
pub type EventType = i32;
pub type Value = Box<Any + 'static + Send>;
pub type Events = HashMap<EventType, Value>;
pub struct EventBox {
mutex: Mutex<bool>, // value doesn't matter.
events: Events,
cond: Condvar,
ignore: Events,
}
impl EventBox {
pub fn new() -> Self {
EventBox {
events: HashMap::new(),
mutex: Mutex::new(false),
cond: Condvar::new(),
ignore: HashMap::new(),
}
}
/// wait: wait for an event(any) to fire
/// if any event is triggered, run callback on events vector
pub fn wait(&mut self, mut callback: Box<FnMut(&mut Events)>) {
let mtx = self.mutex.lock().unwrap();
let num_of_events = self.events.len();
if num_of_events == 0 {
self.cond.wait(mtx);
}
callback(&mut self.events);
}
/// set: fires an event
pub fn set(&mut self, e: EventType, value: Value) {
self.mutex.lock();
let val = self.events.entry(e).or_insert(Box::new(0));
*val = value;
if !self.ignore.contains_key(&e) {
self.cond.notify_all();
}
}
}
unsafe impl Sync for EventBox {}
The problem here is I want to share the EventBox object in two threads, and in order to call set
or wait
, the object need to be mutable. However shared mutable state is not available in rust(not entirely true).
There are several ideas:
- Use
Arc<Mutex<EventBox>>
to share the mutable states between threads. This will not work because when one thread calledeventbox.wait()
, the other thread will not be able to calleventbox.set()
, because it is locked. - Use
Arc<Mutex<T>, CondVar>
in the first place. But then the goal of simplify the code fails. - Use macro to reduce repeated code. While that's good, I'd like not using it in this case.
So dear friend, is there any way to achieve this goal? Any ideas is welcome, Thanks in advance!