use std::any::Any; use std::collections::HashMap; use std::error::Error; #[derive(PartialEq, Eq, Hash, Copy, Clone)] pub struct ObjectId { id: u32, name: &'static str, } pub trait SystemObject { fn as_any(&self) -> &dyn Any; fn get_object_id(&self) -> &ObjectId; fn initialize(&mut self) -> Result<(), Box>; } pub trait ManagedSystemObject: SystemObject + Any {} /// Helper module to manage multiple SystemObject by mapping them using an ObjectId pub struct ObjectManager { obj_map: HashMap>, } impl Default for ObjectManager { fn default() -> Self { Self::new() } } impl ObjectManager { pub fn new() -> ObjectManager { ObjectManager { obj_map: HashMap::new(), } } pub fn insert(&mut self, sys_obj: Box) -> bool { let obj_id = sys_obj.get_object_id(); if self.obj_map.contains_key(obj_id) { return false; } self.obj_map.insert(*obj_id, sys_obj).is_none() } /// Initializes all System Objects in the hash map and returns the number of successful /// initializations pub fn initialize(&mut self) -> Result> { let mut init_success = 0; for val in self.obj_map.values_mut() { if val.initialize().is_ok() { init_success += 1 } } Ok(init_success) } pub fn get(&self, key: &ObjectId) -> Option<&T> { self.obj_map .get(key) .and_then(|o| o.as_ref().as_any().downcast_ref::()) } } #[cfg(test)] mod tests { use crate::core::objects::{ManagedSystemObject, ObjectId, ObjectManager, SystemObject}; use std::any::Any; use std::error::Error; struct ExampleSysObj { id: ObjectId, dummy: u32, was_initialized: bool, } impl ExampleSysObj { fn new(id: ObjectId, dummy: u32) -> ExampleSysObj { ExampleSysObj { id, dummy, was_initialized: false, } } } impl SystemObject for ExampleSysObj { fn as_any(&self) -> &dyn Any { self } fn get_object_id(&self) -> &ObjectId { &self.id } fn initialize(&mut self) -> Result<(), Box> { self.was_initialized = true; Ok(()) } } impl ManagedSystemObject for ExampleSysObj {} struct OtherExampleObject { id: ObjectId, string: String, was_initialized: bool, } impl SystemObject for OtherExampleObject { fn as_any(&self) -> &dyn Any { self } fn get_object_id(&self) -> &ObjectId { &self.id } fn initialize(&mut self) -> Result<(), Box> { self.was_initialized = true; Ok(()) } } impl ManagedSystemObject for OtherExampleObject {} #[test] fn test_obj_manager_simple() { let mut obj_manager = ObjectManager::default(); let expl_obj_id = ObjectId { id: 0, name: "Example 0", }; let example_obj = ExampleSysObj::new(expl_obj_id, 42); assert!(obj_manager.insert(Box::new(example_obj))); let res = obj_manager.initialize(); assert!(res.is_ok()); assert_eq!(res.unwrap(), 1); let obj_back_casted: Option<&ExampleSysObj> = obj_manager.get(&expl_obj_id); assert!(obj_back_casted.is_some()); let expl_obj_back_casted = obj_back_casted.unwrap(); assert_eq!(expl_obj_back_casted.dummy, 42); assert!(expl_obj_back_casted.was_initialized); let second_obj_id = ObjectId { id: 12, name: "Example 1", }; let second_example_obj = OtherExampleObject { id: second_obj_id, string: String::from("Hello Test"), was_initialized: false, }; assert!(obj_manager.insert(Box::new(second_example_obj))); let res = obj_manager.initialize(); assert!(res.is_ok()); assert_eq!(res.unwrap(), 2); let obj_back_casted: Option<&OtherExampleObject> = obj_manager.get(&second_obj_id); assert!(obj_back_casted.is_some()); let expl_obj_back_casted = obj_back_casted.unwrap(); assert_eq!(expl_obj_back_casted.string, String::from("Hello Test")); assert!(expl_obj_back_casted.was_initialized); let existing_obj_id = ObjectId { id: 12, name: "Example 1", }; let invalid_obj = OtherExampleObject { id: existing_obj_id, string: String::from("Hello Test"), was_initialized: false, }; assert_eq!(obj_manager.insert(Box::new(invalid_obj)), false); } }