use std::collections::HashMap;
use std::sync::mpsc::{channel,Sender,sync_channel,SyncSender};
use std::sync::{Arc,Mutex};
use std::thread;
use std::hash::Hash;
use std::fmt::Debug;
pub mod amap_error;
pub use amap_error::AMapErr;
pub trait MKey : 'static +Send + Eq + Hash{}
impl<K> MKey for K where K:'static+Send+Eq+Hash{}
pub trait MVal: 'static +Send {}
impl <V> MVal for V where V:'static+ Send + Debug{}
enum Job<K:MKey,V:MVal> {
Add(K,V,Sender<bool>),
Get(K,Sender<Option< Arc< Mutex<V> > >>),
Remove(K),
}
#[derive(Clone)]
pub struct ArcMap<K:MKey,V:MVal>{
ch:SyncSender<Job<K,V>>,
}
fn hide_map<K:MKey,V:MVal>(bsize:usize)->SyncSender<Job<K,V>>{
let (tx,rx) = sync_channel(bsize);
thread::spawn(move ||{
let mut mp:HashMap<K,Arc<Mutex<V>>> = HashMap::new();
loop {
match rx.recv(){
Ok(Job::Add(k,v,cbak))=>{
mp.insert(k,Arc::new(Mutex::new(v)));
cbak.send(true).unwrap_or(());
}
Ok(Job::Get(ref k,ref cbak))=>{
match mp.get(k) {
Some(ref a)=>cbak.send(Some((*a).clone())).unwrap_or(()),
None=>cbak.send(None).unwrap_or(()),
}
}
Ok(Job::Remove(ref k))=>{
mp.remove(k);
}
_=>return,
}
}
});
tx
}
impl<K:MKey,V:MVal> ArcMap<K,V>{
pub fn new()->ArcMap<K,V>{
ArcMap{
ch:hide_map(20), }
}
pub fn new_sized(bsize:usize)->ArcMap<K,V>{
ArcMap{
ch:hide_map(bsize),
}
}
pub fn insert(&self, k:K,v:V)->Result<bool,AMapErr>{
let (tbak,rbak) = channel();
self.ch.send(Job::Add(k,v,tbak))?;
Ok(rbak.recv()?)
}
pub fn get(&self, k:K)->Result<Arc<Mutex<V>>,AMapErr>{
let (tbak,rbak) = channel();
self.ch.send(Job::Get(k,tbak))?;
match rbak.recv() {
Ok(Some(a))=>Ok(a),
Ok(None)=>Err(AMapErr::NotFound),
Err(d)=>Err(d.into()),
}
}
pub fn remove(&self, k:K)->Result<(),AMapErr>{
self.ch.send(Job::Remove(k))?;
Ok(())
}
pub fn on_do<RT,F>(&mut self, on:K,mut f:F)->Result<RT,AMapErr>
where F:FnMut(&mut V)->RT
{
let p = self.get(on)?;
let mut v = p.lock()?;
Ok(f(&mut v))
}
}
#[cfg(test)]
mod tests{
use super::*;
#[test]
fn add_to_ten(){
let mut mp = ArcMap::new();
for i in 0..10 {
mp.insert(i,0).unwrap();
}
let mut handlers = Vec::new();
for i in 0 .. 10{
for _ in 0 .. 10 {
let n = i;
let m2 = mp.clone();
let h = thread::spawn(move||{
let g = m2.clone().get(n).unwrap();
let mut incnum = g.lock().unwrap();
*incnum +=1;
});
handlers.push(h);
}
}
for i in 0 ..10{
for _ in 0 ..10{
let n = i;
let m2 = mp.clone();
let h = thread::spawn(move||{
m2.clone().on_do(n,|v|*v += 1).unwrap();
});
handlers.push(h);
}
}
for h in handlers {
h.join().unwrap();
}
for i in 0..10 {
mp.on_do(i,|num| assert_eq!(*num,20)).unwrap();
let g = mp.get(i).unwrap();
let num = g.lock().unwrap();
assert_eq!(*num,20);
}
}
}