From 824b15837f7b76fd06fdb7a01e33f7ca7d47fc4c Mon Sep 17 00:00:00 2001 From: Jason Asher Date: Sun, 19 May 2024 16:04:57 -0400 Subject: [PATCH] Implement indexed types for global properties --- .../heterogeneous_container.rs | 37 +++++++++++++------ src/data_containers/mod.rs | 5 +++ src/global_properties.rs | 23 ++++++++++++ 3 files changed, 53 insertions(+), 12 deletions(-) diff --git a/src/data_containers/heterogeneous_container.rs b/src/data_containers/heterogeneous_container.rs index 87d3659..c0a3ba0 100644 --- a/src/data_containers/heterogeneous_container.rs +++ b/src/data_containers/heterogeneous_container.rs @@ -1,12 +1,10 @@ use std::any::Any; -use std::any::TypeId; -use std::collections::HashMap; use std::rc::Rc; use crate::data_containers::Property; pub struct HeterogeneousContainer { - map: HashMap>, + data: Vec>>, } impl Default for HeterogeneousContainer { @@ -17,25 +15,34 @@ impl Default for HeterogeneousContainer { impl HeterogeneousContainer { pub fn new() -> HeterogeneousContainer { - HeterogeneousContainer { - map: HashMap::new(), - } + HeterogeneousContainer { data: Vec::new() } } pub fn set_value(&mut self, value: K::Value) { - self.map.insert(TypeId::of::(), Rc::new(value)); + let property_index = K::index(); + if property_index >= self.data.len() { + self.data.resize_with(property_index + 1, || None) + } + self.data[property_index] = Some(Rc::new(value)); } pub fn get_value(&self) -> Option<&K::Value> { - match self.map.get(&TypeId::of::()) { - None => None, - Some(boxed_value) => boxed_value.downcast_ref::(), + let property_index = K::index(); + if property_index >= self.data.len() { + return None; } + self.data[property_index] + .as_ref() + .map(|boxed_value| boxed_value.downcast_ref::().unwrap()) } pub fn get_rc_value(&self) -> Option> { - self.map - .get(&TypeId::of::()) + let property_index = K::index(); + if property_index >= self.data.len() { + return None; + } + self.data[property_index] + .as_ref() .map(|boxed_value| Rc::clone(boxed_value).downcast::().unwrap()) } } @@ -46,11 +53,17 @@ mod tests { struct KeyOne {} impl Property for KeyOne { type Value = usize; + fn index() -> usize { + 0 + } } struct KeyTwo {} impl Property for KeyTwo { type Value = bool; + fn index() -> usize { + 1 + } } #[test] diff --git a/src/data_containers/mod.rs b/src/data_containers/mod.rs index 6995716..631fb8e 100644 --- a/src/data_containers/mod.rs +++ b/src/data_containers/mod.rs @@ -15,6 +15,7 @@ pub mod vector_person_container; pub trait Property: Any { type Value: Any; + fn index() -> usize; } pub trait PropertyWithDefault: Any { @@ -25,6 +26,10 @@ pub trait PropertyWithDefault: Any { impl Property for T { type Value = T::Value; + + fn index() -> usize { + T::index() + } } pub trait PersonContainer { diff --git a/src/global_properties.rs b/src/global_properties.rs index ac84c3d..eb9928b 100644 --- a/src/global_properties.rs +++ b/src/global_properties.rs @@ -1,6 +1,8 @@ use std::any::{Any, TypeId}; use std::collections::HashMap; use std::rc::Rc; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::Mutex; use crate::context::Context; use crate::data_containers::heterogeneous_container::HeterogeneousContainer; @@ -9,6 +11,17 @@ use crate::data_containers::Property; // TODO: Decide if we want default global property values pub trait GlobalProperty: Property {} +static INDEX: Mutex = Mutex::new(0); + +pub fn next(index: &AtomicUsize) -> usize { + let mut guard = INDEX.lock().unwrap(); + if index.load(Ordering::SeqCst) == usize::MAX { + index.store(*guard, Ordering::SeqCst); + *guard += 1; + } + index.load(Ordering::Relaxed) +} + #[macro_export] macro_rules! define_global_property { ($global_property:ident, $value:ty) => { @@ -16,6 +29,16 @@ macro_rules! define_global_property { impl $crate::data_containers::Property for $global_property { type Value = $value; + + fn index() -> usize { + static INDEX: std::sync::atomic::AtomicUsize = + std::sync::atomic::AtomicUsize::new(usize::MAX); + let mut index = INDEX.load(std::sync::atomic::Ordering::Relaxed); + if index == usize::MAX { + index = $crate::global_properties::next(&INDEX); + } + index + } } impl $crate::global_properties::GlobalProperty for $global_property {}