satrs_core/
objects.rs

1//! # Module providing addressable object support and a manager for them
2//!
3//! Each addressable object can be identified using an [object ID][ObjectId].
4//! The [system object][ManagedSystemObject] trait also allows storing these objects into the
5//! [object manager][ObjectManager]. They can then be retrieved and casted back to a known type
6//! using the object ID.
7//!
8//! # Examples
9//!
10//! ```rust
11//! use std::any::Any;
12//! use std::error::Error;
13//! use satrs_core::objects::{ManagedSystemObject, ObjectId, ObjectManager, SystemObject};
14//!
15//! struct ExampleSysObj {
16//!     id: ObjectId,
17//!     dummy: u32,
18//!     was_initialized: bool,
19//! }
20//!
21//! impl ExampleSysObj {
22//!     fn new(id: ObjectId, dummy: u32) -> ExampleSysObj {
23//!         ExampleSysObj {
24//!             id,
25//!             dummy,
26//!             was_initialized: false,
27//!         }
28//!     }
29//! }
30//!
31//! impl SystemObject for ExampleSysObj {
32//!     type Error = ();
33//!     fn get_object_id(&self) -> &ObjectId {
34//!         &self.id
35//!     }
36//!
37//!     fn initialize(&mut self) -> Result<(), Self::Error> {
38//!         self.was_initialized = true;
39//!         Ok(())
40//!     }
41//! }
42//!
43//! impl ManagedSystemObject for ExampleSysObj {}
44//!
45//!  let mut obj_manager = ObjectManager::default();
46//!  let obj_id = ObjectId { id: 0, name: "Example 0"};
47//!  let example_obj = ExampleSysObj::new(obj_id, 42);
48//!  obj_manager.insert(Box::new(example_obj));
49//!  let obj_back_casted: Option<&ExampleSysObj> = obj_manager.get_ref(&obj_id);
50//!  let example_obj = obj_back_casted.unwrap();
51//!  assert_eq!(example_obj.id, obj_id);
52//!  assert_eq!(example_obj.dummy, 42);
53//! ```
54use crate::tmtc::TargetId;
55#[cfg(feature = "alloc")]
56use alloc::boxed::Box;
57#[cfg(feature = "alloc")]
58pub use alloc_mod::*;
59#[cfg(feature = "alloc")]
60use downcast_rs::Downcast;
61#[cfg(feature = "alloc")]
62use hashbrown::HashMap;
63#[cfg(feature = "std")]
64use std::error::Error;
65
66#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
67pub struct ObjectId {
68    pub id: TargetId,
69    pub name: &'static str,
70}
71
72#[cfg(feature = "alloc")]
73pub mod alloc_mod {
74    use super::*;
75
76    /// Each object which is stored inside the [object manager][ObjectManager] needs to implemented
77    /// this trait
78    pub trait SystemObject: Downcast {
79        type Error;
80        fn get_object_id(&self) -> &ObjectId;
81        fn initialize(&mut self) -> Result<(), Self::Error>;
82    }
83    downcast_rs::impl_downcast!(SystemObject assoc Error);
84
85    pub trait ManagedSystemObject: SystemObject + Send {}
86    downcast_rs::impl_downcast!(ManagedSystemObject assoc Error);
87
88    /// Helper module to manage multiple [ManagedSystemObjects][ManagedSystemObject] by mapping them
89    /// using an [object ID][ObjectId]
90    #[cfg(feature = "alloc")]
91    pub struct ObjectManager<E> {
92        obj_map: HashMap<ObjectId, Box<dyn ManagedSystemObject<Error = E>>>,
93    }
94
95    #[cfg(feature = "alloc")]
96    impl<E: 'static> Default for ObjectManager<E> {
97        fn default() -> Self {
98            Self::new()
99        }
100    }
101
102    #[cfg(feature = "alloc")]
103    impl<E: 'static> ObjectManager<E> {
104        pub fn new() -> Self {
105            ObjectManager {
106                obj_map: HashMap::new(),
107            }
108        }
109        pub fn insert(&mut self, sys_obj: Box<dyn ManagedSystemObject<Error = E>>) -> bool {
110            let obj_id = sys_obj.get_object_id();
111            if self.obj_map.contains_key(obj_id) {
112                return false;
113            }
114            self.obj_map.insert(*obj_id, sys_obj).is_none()
115        }
116
117        /// Initializes all System Objects in the hash map and returns the number of successful
118        /// initializations
119        pub fn initialize(&mut self) -> Result<u32, Box<dyn Error>> {
120            let mut init_success = 0;
121            for val in self.obj_map.values_mut() {
122                if val.initialize().is_ok() {
123                    init_success += 1
124                }
125            }
126            Ok(init_success)
127        }
128
129        /// Retrieve a reference to an object stored inside the manager. The type to retrieve needs to
130        /// be explicitly passed as a generic parameter or specified on the left hand side of the
131        /// expression.
132        pub fn get_ref<T: ManagedSystemObject<Error = E>>(&self, key: &ObjectId) -> Option<&T> {
133            self.obj_map.get(key).and_then(|o| o.downcast_ref::<T>())
134        }
135
136        /// Retrieve a mutable reference to an object stored inside the manager. The type to retrieve
137        /// needs to be explicitly passed as a generic parameter or specified on the left hand side
138        /// of the expression.
139        pub fn get_mut<T: ManagedSystemObject<Error = E>>(
140            &mut self,
141            key: &ObjectId,
142        ) -> Option<&mut T> {
143            self.obj_map
144                .get_mut(key)
145                .and_then(|o| o.downcast_mut::<T>())
146        }
147    }
148}
149
150#[cfg(test)]
151mod tests {
152    use crate::objects::{ManagedSystemObject, ObjectId, ObjectManager, SystemObject};
153    use std::boxed::Box;
154    use std::string::String;
155    use std::sync::{Arc, Mutex};
156    use std::thread;
157
158    struct ExampleSysObj {
159        id: ObjectId,
160        dummy: u32,
161        was_initialized: bool,
162    }
163
164    impl ExampleSysObj {
165        fn new(id: ObjectId, dummy: u32) -> ExampleSysObj {
166            ExampleSysObj {
167                id,
168                dummy,
169                was_initialized: false,
170            }
171        }
172    }
173
174    impl SystemObject for ExampleSysObj {
175        type Error = ();
176        fn get_object_id(&self) -> &ObjectId {
177            &self.id
178        }
179
180        fn initialize(&mut self) -> Result<(), Self::Error> {
181            self.was_initialized = true;
182            Ok(())
183        }
184    }
185
186    impl ManagedSystemObject for ExampleSysObj {}
187
188    struct OtherExampleObject {
189        id: ObjectId,
190        string: String,
191        was_initialized: bool,
192    }
193
194    impl SystemObject for OtherExampleObject {
195        type Error = ();
196        fn get_object_id(&self) -> &ObjectId {
197            &self.id
198        }
199
200        fn initialize(&mut self) -> Result<(), Self::Error> {
201            self.was_initialized = true;
202            Ok(())
203        }
204    }
205
206    impl ManagedSystemObject for OtherExampleObject {}
207
208    #[test]
209    fn test_obj_manager_simple() {
210        let mut obj_manager = ObjectManager::default();
211        let expl_obj_id = ObjectId {
212            id: 0,
213            name: "Example 0",
214        };
215        let example_obj = ExampleSysObj::new(expl_obj_id, 42);
216        assert!(obj_manager.insert(Box::new(example_obj)));
217        let res = obj_manager.initialize();
218        assert!(res.is_ok());
219        assert_eq!(res.unwrap(), 1);
220        let obj_back_casted: Option<&ExampleSysObj> = obj_manager.get_ref(&expl_obj_id);
221        assert!(obj_back_casted.is_some());
222        let expl_obj_back_casted = obj_back_casted.unwrap();
223        assert_eq!(expl_obj_back_casted.dummy, 42);
224        assert!(expl_obj_back_casted.was_initialized);
225
226        let second_obj_id = ObjectId {
227            id: 12,
228            name: "Example 1",
229        };
230        let second_example_obj = OtherExampleObject {
231            id: second_obj_id,
232            string: String::from("Hello Test"),
233            was_initialized: false,
234        };
235
236        assert!(obj_manager.insert(Box::new(second_example_obj)));
237        let res = obj_manager.initialize();
238        assert!(res.is_ok());
239        assert_eq!(res.unwrap(), 2);
240        let obj_back_casted: Option<&OtherExampleObject> = obj_manager.get_ref(&second_obj_id);
241        assert!(obj_back_casted.is_some());
242        let expl_obj_back_casted = obj_back_casted.unwrap();
243        assert_eq!(expl_obj_back_casted.string, String::from("Hello Test"));
244        assert!(expl_obj_back_casted.was_initialized);
245
246        let existing_obj_id = ObjectId {
247            id: 12,
248            name: "Example 1",
249        };
250        let invalid_obj = OtherExampleObject {
251            id: existing_obj_id,
252            string: String::from("Hello Test"),
253            was_initialized: false,
254        };
255
256        assert!(!obj_manager.insert(Box::new(invalid_obj)));
257    }
258
259    #[test]
260    fn object_man_threaded() {
261        let obj_manager = Arc::new(Mutex::new(ObjectManager::new()));
262        let expl_obj_id = ObjectId {
263            id: 0,
264            name: "Example 0",
265        };
266        let example_obj = ExampleSysObj::new(expl_obj_id, 42);
267        let second_obj_id = ObjectId {
268            id: 12,
269            name: "Example 1",
270        };
271        let second_example_obj = OtherExampleObject {
272            id: second_obj_id,
273            string: String::from("Hello Test"),
274            was_initialized: false,
275        };
276
277        let mut obj_man_handle = obj_manager.lock().expect("Mutex lock failed");
278        assert!(obj_man_handle.insert(Box::new(example_obj)));
279        assert!(obj_man_handle.insert(Box::new(second_example_obj)));
280        let res = obj_man_handle.initialize();
281        std::mem::drop(obj_man_handle);
282        assert!(res.is_ok());
283        assert_eq!(res.unwrap(), 2);
284        let obj_man_0 = obj_manager.clone();
285        let jh0 = thread::spawn(move || {
286            let locked_man = obj_man_0.lock().expect("Mutex lock failed");
287            let obj_back_casted: Option<&ExampleSysObj> = locked_man.get_ref(&expl_obj_id);
288            assert!(obj_back_casted.is_some());
289            let expl_obj_back_casted = obj_back_casted.unwrap();
290            assert_eq!(expl_obj_back_casted.dummy, 42);
291            assert!(expl_obj_back_casted.was_initialized);
292            std::mem::drop(locked_man)
293        });
294
295        let jh1 = thread::spawn(move || {
296            let locked_man = obj_manager.lock().expect("Mutex lock failed");
297            let obj_back_casted: Option<&OtherExampleObject> = locked_man.get_ref(&second_obj_id);
298            assert!(obj_back_casted.is_some());
299            let expl_obj_back_casted = obj_back_casted.unwrap();
300            assert_eq!(expl_obj_back_casted.string, String::from("Hello Test"));
301            assert!(expl_obj_back_casted.was_initialized);
302            std::mem::drop(locked_man)
303        });
304        jh0.join().expect("Joining thread 0 failed");
305        jh1.join().expect("Joining thread 1 failed");
306    }
307}