use std::any::{Any, TypeId};
use std::collections::HashMap;
use unsafe_any::UnsafeAny;
use parameter::*;
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
enum Key {
String(String),
Id(TypeId),
}
macro_rules! implement {
($name:ident,$param:ident, $any_base:ident, $(+ $bounds:ident)*) => {
#[allow(dead_code)]
pub struct $name {
map: HashMap<Key, $param>,
type_map: HashMap<Key, TypeId>,
}
impl $name {
#![allow(dead_code)]
pub fn new() -> $name {
$name {
map: HashMap::new(),
type_map: HashMap::new(),
}
}
pub fn insert_with_name<S: Into<String> + Clone, V: $any_base $(+ $bounds)*>(&mut self, key: S, value: V) -> Option<V> {
self.type_map.insert(Key::String(key.clone().into()), TypeId::of::<V>());
self.map.insert(Key::String(key.clone().into()), $param::new(key, value))
.and_then(|old_value| old_value.get_value())
.map(|boxed_value| *boxed_value)
.unwrap_or(None)
}
pub fn insert_with_type<V: $any_base $(+ $bounds)*>(&mut self, value: V) -> Option<V> {
self.type_map.insert(Key::Id(TypeId::of::<V>()), TypeId::of::<V>());
self.map.insert(Key::Id(TypeId::of::<V>()), $param::new::<String, V>("(dummy name)".to_string(), value))
.and_then(|old_value| old_value.get_value())
.map(|boxed_value| *boxed_value)
.unwrap_or(None)
}
pub fn remove_with_name<V: $any_base $(+ $bounds)*>(&mut self, key: &str) -> Option<Box<V>> {
match self.type_map.get(&Key::String(key.into())) {
Some(registered_type) => {
if *registered_type == TypeId::of::<V>() {
self.map.remove(&Key::String(key.into()))
.map(|parameter| parameter.get_value::<V>())
.unwrap_or(None)
} else {
None
}
},
None => None,
}
}
pub fn remove_with_type<V: $any_base $(+ $bounds)*>(&mut self) -> Option<Box<V>> {
match self.type_map.get(&Key::Id(TypeId::of::<V>())) {
Some(registered_type) => {
if *registered_type == TypeId::of::<V>() {
self.map.remove(&Key::Id(TypeId::of::<V>()))
.map(|parameter| parameter.get_value::<V>())
.unwrap_or(None)
} else {
None
}
},
None => None,
}
}
}
}
}
implement!(ParameterMap,Parameter,Any,);
implement!(SendParameterMap,SendParameter,Any,+Send);
implement!(UnsafeParameterMap,UnsafeParameter,UnsafeAny,);
implement!(UnsafeSendSyncParameterMap,UnsafeSendSyncParameter,UnsafeAny,+Send+Sync);
impl ::std::fmt::Debug for ParameterMap {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
write!(f, "ParameterMap {{Â map: {:?}, type_map: {:?} }}", &self.map, &self.type_map)
}
}
#[cfg(test)]
mod tests {
#![allow(non_snake_case)]
use super::ParameterMap;
use parameter::*;
#[test]
fn ParameterMap_test_insert_remove() {
let mut map: ParameterMap = ParameterMap::new();
map.insert_with_name("key 1", "value 1".to_string());
map.insert_with_name("key 2", "value 2");
map.insert_with_name("key 3", 123 as usize);
map.insert_with_name("key 4", 123.323 as f32);
map.insert_with_name("key 4", true);
let x = *map.remove_with_name::<String>("key 1").unwrap();
assert_eq!(x, "value 1".to_string());
let x = map.remove_with_name::<Parameter>("key 2");
assert!(x.is_none());
assert_eq!(
*map.remove_with_name::<usize>(&"key 3".to_string()).unwrap(),
123
);
assert_eq!(*map.remove_with_name::<bool>("key 4").unwrap(), true);
let mut map: ParameterMap = ParameterMap::new();
map.insert_with_type("value 1".to_string());
map.insert_with_type("value 2");
map.insert_with_type(123 as usize);
map.insert_with_type(123.323 as f32);
map.insert_with_type(true);
let x = *map.remove_with_type::<String>().unwrap();
assert_eq!(x, "value 1".to_string());
let x = map.remove_with_type::<Parameter>();
assert!(x.is_none());
assert_eq!(*map.remove_with_type::<usize>().unwrap(), 123);
assert_eq!(*map.remove_with_type::<bool>().unwrap(), true); }
#[test]
fn UnsafeSendSyncParameterMap() {
let mut map: UnsafeSendSyncParameterMap = UnsafeSendSyncParameterMap::new();
map.insert_with_name("key 1", "value 1".to_string());
map.insert_with_name("key 2", "value 2");
map.insert_with_name("key 3", 123 as usize);
map.insert_with_name("key 4", 123.323 as f32);
map.insert_with_name("key 4", true);
let x = *map.remove_with_name::<String>("key 1").unwrap();
assert_eq!(x, "value 1".to_string());
let x = map.remove_with_name::<UnsafeSendSyncParameter>("key 2");
assert!(x.is_none());
assert_eq!(
*map.remove_with_name::<usize>(&"key 3".to_string()).unwrap(),
123
);
assert_eq!(*map.remove_with_name::<bool>("key 4").unwrap(), true);
let mut map: UnsafeSendSyncParameterMap = UnsafeSendSyncParameterMap::new();
map.insert_with_type("value 1".to_string());
map.insert_with_type("value 2");
map.insert_with_type(123 as usize);
map.insert_with_type(123.323 as f32);
map.insert_with_type(true);
let x = *map.remove_with_type::<String>().unwrap();
assert_eq!(x, "value 1".to_string());
let x = map.remove_with_type::<UnsafeSendSyncParameter>();
assert!(x.is_none());
assert_eq!(*map.remove_with_type::<usize>().unwrap(), 123);
assert_eq!(*map.remove_with_type::<bool>().unwrap(), true); }
}