1use 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 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 #[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 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 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 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}