use std::{
any::{Any, TypeId},
collections::HashMap,
hash::Hash,
fmt
};
pub struct Params {
inner: HashMap<TypeId, Box<dyn Any + Send + Sync>>,
}
impl Params {
pub fn new() -> Self {
Self {
inner: HashMap::new()
}
}
pub fn set<T: 'static + Send + Sync>(&mut self, value: T) {
self.inner.insert(TypeId::of::<T>(), Box::new(value));
}
pub fn get<T: 'static + Send + Sync>(&self) -> Option<&T> {
self.inner
.get(&TypeId::of::<T>())
.and_then(|boxed| boxed.downcast_ref::<T>())
}
pub fn get_mut<T: 'static + Send + Sync>(&mut self) -> Option<&mut T> {
self.inner
.get_mut(&TypeId::of::<T>())
.and_then(|boxed| boxed.downcast_mut::<T>())
}
pub fn take<T: 'static + Send + Sync>(&mut self) -> Option<T> {
self.inner
.remove(&TypeId::of::<T>())
.and_then(|boxed| boxed.downcast::<T>().ok())
.map(|boxed| *boxed)
}
}
impl fmt::Display for Params {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Params(types=[")?;
for (i, ty) in self.inner.keys().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{:?}", ty)?;
}
write!(f, "])")
}
}
impl fmt::Debug for Params {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let types: Vec<_> = self.inner.keys().collect();
f.debug_struct("Params")
.field("types", &types)
.finish()
}
}
impl Default for Params {
fn default() -> Self {
Self::new()
}
}
pub struct Locals {
inner: HashMap<String, Box<dyn Any + Send + Sync>>
}
impl Locals {
pub fn new() -> Self {
Self {
inner: HashMap::new()
}
}
pub fn set<T: 'static + Send + Sync>(&mut self, key: impl Into<String>, value: T) {
self.inner.insert(key.into(), Box::new(value));
}
pub fn get<T: 'static + Send + Sync>(&self, key: &str) -> Option<&T> {
self.inner
.get(key)
.and_then(|boxed| boxed.downcast_ref::<T>())
}
pub fn get_mut<T: 'static + Send + Sync>(&mut self, key: &str) -> Option<&mut T> {
self.inner
.get_mut(key)
.and_then(|boxed| boxed.downcast_mut::<T>())
}
pub fn take<T: 'static + Send + Sync>(&mut self, key: &str) -> Option<T> {
if let Some(boxed_any) = self.inner.get(key) {
if boxed_any.downcast_ref::<T>().is_some() {
let any_box = self.inner.remove(key).unwrap();
return any_box.downcast::<T>().ok().map(|boxed_t| *boxed_t);
}
}
None
}
pub fn keys(&self) -> Vec<&str> {
self.inner.keys().map(|s| s.as_str()).collect()
}
pub fn export_param<T: 'static + Clone + Send + Sync>(&mut self, params: &Params, key: impl Into<String>) {
if let Some(value) = params.get::<T>() {
let cloned = value.clone();
self.set(key, cloned);
}
}
pub fn import_param<T: 'static + Clone + Send + Sync>(&mut self, params: &mut Params, key: &str) {
if let Some(value) = self.get::<T>(key) {
let cloned = value.clone();
params.set(cloned);
}
}
}
impl fmt::Display for Locals {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let keys: Vec<&str> = self.inner.keys().map(|k| k.as_str()).collect();
write!(f, "Locals(keys={:?})", keys)
}
}
impl fmt::Debug for Locals {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let keys: Vec<&str> = self.inner.keys().map(|k| k.as_str()).collect();
f.debug_struct("Locals")
.field("keys", &keys)
.finish()
}
}
impl Default for Locals {
fn default() -> Self {
Self::new()
}
}
pub trait ParamValue: Any + Send + Sync + 'static {
fn clone_box(&self) -> Box<dyn ParamValue>;
fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any;
}
impl<T> ParamValue for T
where
T: Any + Clone + Send + Sync + 'static,
{
fn clone_box(&self) -> Box<dyn ParamValue> {
Box::new(self.clone())
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
pub struct ParamsClone {
inner: HashMap<TypeId, Box<dyn ParamValue>>,
}
impl ParamsClone {
pub fn new() -> Self {
Self {
inner: HashMap::new(),
}
}
pub fn set<T: ParamValue>(&mut self, value: T) {
self.inner.insert(TypeId::of::<T>(), Box::new(value));
}
pub fn get<T: 'static + Send + Sync>(&self) -> Option<&T> {
self.inner
.get(&TypeId::of::<T>())
.and_then(|boxed| (&**boxed as &dyn Any).downcast_ref::<T>())
}
pub fn get_mut<T: 'static + Send + Sync>(&mut self) -> Option<&mut T> {
self.inner
.get_mut(&TypeId::of::<T>())
.and_then(|boxed| (&mut **boxed as &mut dyn Any).downcast_mut::<T>())
}
pub fn take<T: 'static + Send + Sync>(&mut self) -> Option<T> {
self.inner
.remove(&TypeId::of::<T>())
.and_then(|boxed| {
let any_box: Box<dyn Any> = boxed;
any_box.downcast().ok()
})
.map(|boxed| *boxed)
}
pub fn combine(&mut self, other: &Self) {
for (ty, value) in &other.inner {
self.inner.entry(*ty).or_insert((**value).clone_box());
}
}
pub fn merge(&mut self, other: &Self) {
for (ty, value) in &other.inner {
self.inner.insert(*ty, (**value).clone_box());
}
}
}
impl Clone for ParamsClone {
fn clone(&self) -> Self {
let mut output = ParamsClone::default();
output.combine(self);
output
}
}
impl fmt::Display for ParamsClone {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "ParamsClone(types=[")?;
for (i, ty) in self.inner.keys().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{:?}", ty)?;
}
write!(f, "])")
}
}
impl fmt::Debug for ParamsClone {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let types: Vec<_> = self.inner.keys().collect();
f.debug_struct("ParamsClone")
.field("types", &types)
.finish()
}
}
impl Default for ParamsClone {
fn default() -> Self {
Self::new()
}
}
pub struct LocalsClone {
inner: HashMap<String, Box<dyn ParamValue>>,
}
impl LocalsClone {
pub fn new() -> Self {
Self {
inner: HashMap::new(),
}
}
pub fn set<T: ParamValue>(&mut self, key: impl Into<String>, value: T) {
self.inner.insert(key.into(), Box::new(value));
}
pub fn get<T: ParamValue>(&self, key: &str) -> Option<&T> {
self.inner
.get(key)
.and_then(|boxed| (&**boxed as &dyn Any).downcast_ref::<T>())
}
pub fn get_mut<T: ParamValue>(&mut self, key: &str) -> Option<&mut T> {
self.inner
.get_mut(key)
.and_then(|boxed| boxed.as_any_mut().downcast_mut::<T>())
}
pub fn take<T: ParamValue + Clone>(&mut self, key: &str) -> Option<T> {
if let Some(val) = self.get::<T>(key) {
let cloned = (*val).clone();
self.inner.remove(key);
Some(cloned)
} else {
None
}
}
pub fn keys(&self) -> Vec<&str> {
self.inner.keys().map(String::as_str).collect()
}
pub fn export_param<T: ParamValue + Clone>(&mut self, params: &ParamsClone, key: impl Into<String>) {
if let Some(value) = params.get::<T>() {
self.set(key, (*value).clone());
}
}
pub fn import_param<T: ParamValue + Clone>(&mut self, params: &mut ParamsClone, key: &str) {
if let Some(value) = self.get::<T>(key) {
params.set((*value).clone());
}
}
pub fn combine(&mut self, other: &LocalsClone) {
for (key, value) in &other.inner {
self.inner.entry((*key).clone()).or_insert((**value).clone_box());
}
}
pub fn merge(&mut self, other: &LocalsClone) {
for (key, value) in &other.inner {
self.inner.insert((*key).clone(), (**value).clone_box());
}
}
}
impl Clone for LocalsClone {
fn clone(&self) -> Self {
let mut output = LocalsClone::default();
output.combine(self);
output
}
}
impl fmt::Display for LocalsClone {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let keys: Vec<&str> = self.inner.keys().map(String::as_str).collect();
write!(f, "LocalsClone(keys={:?})", keys)
}
}
impl fmt::Debug for LocalsClone {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let keys: Vec<&str> = self.inner.keys().map(String::as_str).collect();
f.debug_struct("LocalsClone")
.field("keys", &keys)
.finish()
}
}
impl Default for LocalsClone {
fn default() -> Self {
Self::new()
}
}
pub fn combine_hashmap<K, V>(a: &mut HashMap<K, V>, b: &HashMap<K, V>)
where
K: Eq + Hash + Clone,
V: Clone,
{
for (key, value) in b {
a.entry(key.clone()).or_insert_with(|| value.clone());
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::HashMap;
#[test]
fn test_param_value_clone_box_and_as_any() {
let x = 42u8;
let boxed: Box<dyn ParamValue> = x.clone_box();
let y = boxed.as_any().downcast_ref::<u8>().unwrap();
assert_eq!(*y, 42u8);
}
#[test]
fn test_params_set_get() {
let mut p = ParamsClone::default();
p.set(100i32);
assert_eq!(p.get::<i32>(), Some(&100));
}
#[test]
fn test_params_replace() {
let mut p = ParamsClone::default();
p.set(1i32);
p.set(2i32);
assert_eq!(p.get::<i32>(), Some(&2));
}
#[test]
fn test_params_get_mut() {
let mut p = ParamsClone::default();
p.set(10i32);
if let Some(v) = p.get_mut::<i32>() { *v += 5; }
assert_eq!(p.get::<i32>(), Some(&15));
}
#[test]
fn test_params_take() {
let mut p = ParamsClone::default();
p.set(String::from("hello"));
let v = p.take::<String>().unwrap();
assert_eq!(v, "hello");
assert!(p.get::<String>().is_none());
}
#[test]
fn test_params_combine() {
let mut a = ParamsClone::default();
a.set(1u8);
let mut b = ParamsClone::default();
b.set(2u8);
a.combine(&b);
assert_eq!(a.get::<u8>(), Some(&1));
}
#[test]
fn test_locals_set_get() {
let mut l = LocalsClone::default();
l.set("foo", 123i32);
assert_eq!(l.get::<i32>("foo"), Some(&123));
}
#[test]
fn test_locals_get_mut_and_take() {
let mut l = LocalsClone::default();
l.set("vec", vec![1, 2, 3]);
if let Some(v) = l.get_mut::<Vec<i32>>("vec") { v.push(4); }
assert_eq!(l.get::<Vec<i32>>("vec"), Some(&vec![1, 2, 3, 4]));
let v = l.take::<Vec<i32>>("vec").unwrap();
assert_eq!(v, vec![1, 2, 3, 4]);
assert!(l.get::<Vec<i32>>("vec").is_none());
}
#[test]
fn test_locals_keys() {
let mut l = LocalsClone::default();
l.set("a", true);
l.set("b", false);
let mut keys = l.keys();
keys.sort();
assert_eq!(keys, vec!["a", "b"]);
}
#[test]
fn test_locals_combine() {
let mut a = LocalsClone::default();
a.set("x", 1i32);
let mut b = LocalsClone::default();
b.set("y", 2i32);
a.combine(&b);
assert_eq!(a.get::<i32>("x"), Some(&1));
assert_eq!(a.get::<i32>("y"), Some(&2));
}
#[test]
fn test_combine_hashmap() {
let mut a: HashMap<String, i32> = HashMap::new();
a.insert("key1".to_string(), 1);
let mut b = HashMap::new();
b.insert("key2".to_string(), 2);
b.insert("key1".to_string(), 9);
combine_hashmap(&mut a, &b);
assert_eq!(a.get("key1"), Some(&1));
assert_eq!(a.get("key2"), Some(&2));
}
#[test]
fn test_params_get_wrong_type_and_missing() {
let mut p = Params::default();
p.set(42u8);
assert!(p.get::<u16>().is_none());
assert!(p.get_mut::<u16>().is_none());
assert!(p.take::<u16>().is_none());
assert_eq!(p.get::<u8>(), Some(&42u8));
assert!(p.get_mut::<u8>().is_some());
let val = p.take::<u8>().unwrap();
assert_eq!(val, 42u8);
assert!(p.get::<u8>().is_none());
}
#[test]
fn test_locals_get_wrong_type_and_missing() {
let mut l = Locals::default();
l.set("foo", 123i32);
assert!(l.get::<u64>("foo").is_none());
assert!(l.get::<i32>("bar").is_none());
assert!(l.get_mut::<i32>("bar").is_none());
assert!(l.get_mut::<u64>("foo").is_none());
assert!(l.take::<u64>("foo").is_none());
assert!(l.take::<i32>("bar").is_none());
assert_eq!(l.get::<i32>("foo"), Some(&123));
assert!(l.get_mut::<i32>("foo").is_some());
let val = l.take::<i32>("foo").unwrap();
assert_eq!(val, 123);
assert!(l.get::<i32>("foo").is_none());
}
#[test]
fn test_paramsclone_clone_preserves_entries() {
let mut original = ParamsClone::default();
original.set(String::from("foo"));
let cloned = original.clone();
assert_eq!(cloned.get::<String>(), Some(&String::from("foo")));
assert_eq!(original.get::<String>(), Some(&String::from("foo")));
}
#[test]
fn test_paramsclone_clone_independence() {
let mut original = ParamsClone::default();
original.set(10u8);
let mut cloned = original.clone();
cloned.set(20u8);
assert_eq!(original.get::<u8>(), Some(&10u8));
assert_eq!(cloned.get::<u8>(), Some(&20u8));
}
#[test]
fn test_localsclone_clone_preserves_entries() {
let mut original = LocalsClone::default();
original.set("key", String::from("value"));
let cloned = original.clone();
assert_eq!(cloned.get::<String>("key"), Some(&String::from("value")));
assert_eq!(original.get::<String>("key"), Some(&String::from("value")));
}
#[test]
fn test_localsclone_clone_independence() {
let mut original = LocalsClone::default();
original.set("counter", 1i32);
let mut cloned = original.clone();
cloned.set("counter", 2i32);
assert_eq!(original.get::<i32>("counter"), Some(&1));
assert_eq!(cloned.get::<i32>("counter"), Some(&2));
}
}