use Downcast for Object Manager
This commit is contained in:
parent
44d1c6cf97
commit
287f67a477
@ -7,7 +7,7 @@
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! ```
|
||||
//! ```rust
|
||||
//! use std::any::Any;
|
||||
//! use std::error::Error;
|
||||
//! use fsrc_core::objects::{ManagedSystemObject, ObjectId, ObjectManager, SystemObject};
|
||||
@ -29,9 +29,6 @@
|
||||
//! }
|
||||
//!
|
||||
//! impl SystemObject for ExampleSysObj {
|
||||
//! fn as_any(&self) -> &dyn Any {
|
||||
//! self
|
||||
//! }
|
||||
//!
|
||||
//! fn get_object_id(&self) -> &ObjectId {
|
||||
//! &self.id
|
||||
@ -39,24 +36,23 @@
|
||||
//!
|
||||
//! fn initialize(&mut self) -> Result<(), Box<dyn Error>> {
|
||||
//! self.was_initialized = true;
|
||||
//! Ok(())
|
||||
//! }
|
||||
//! Ok(())
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! impl ManagedSystemObject for ExampleSysObj {}
|
||||
//!
|
||||
//!
|
||||
//! let mut obj_manager = ObjectManager::default();
|
||||
//! let obj_id = ObjectId { id: 0, name: "Example 0"};
|
||||
//! let example_obj = ExampleSysObj::new(obj_id, 42);
|
||||
//! obj_manager.insert(Box::new(example_obj));
|
||||
//! let obj_back_casted: Option<&ExampleSysObj> = obj_manager.get(&obj_id);
|
||||
//! let obj_back_casted: Option<&ExampleSysObj> = obj_manager.get_ref(&obj_id);
|
||||
//! let example_obj = obj_back_casted.unwrap();
|
||||
//! assert_eq!(example_obj.id, obj_id);
|
||||
//! assert_eq!(example_obj.dummy, 42);
|
||||
//! ```
|
||||
|
||||
use std::any::Any;
|
||||
use downcast_rs::Downcast;
|
||||
use std::collections::HashMap;
|
||||
use std::error::Error;
|
||||
|
||||
@ -68,13 +64,14 @@ pub struct ObjectId {
|
||||
|
||||
/// Each object which is stored inside the [object manager][ObjectManager] needs to implemented
|
||||
/// this trait
|
||||
pub trait SystemObject {
|
||||
fn as_any(&self) -> &dyn Any;
|
||||
pub trait SystemObject: Downcast {
|
||||
fn get_object_id(&self) -> &ObjectId;
|
||||
fn initialize(&mut self) -> Result<(), Box<dyn Error>>;
|
||||
}
|
||||
downcast_rs::impl_downcast!(SystemObject);
|
||||
|
||||
pub trait ManagedSystemObject: SystemObject + Any + Send {}
|
||||
pub trait ManagedSystemObject: SystemObject + Send {}
|
||||
downcast_rs::impl_downcast!(ManagedSystemObject);
|
||||
|
||||
/// Helper module to manage multiple [ManagedSystemObjects][ManagedSystemObject] by mapping them
|
||||
/// using an [object ID][ObjectId]
|
||||
@ -114,19 +111,26 @@ impl ObjectManager {
|
||||
Ok(init_success)
|
||||
}
|
||||
|
||||
/// Retrieve an object stored inside the manager. The type to retrieve needs to be explicitly
|
||||
/// passed as a generic parameter
|
||||
pub fn get<T: Any>(&self, key: &ObjectId) -> Option<&T> {
|
||||
/// Retrieve a reference to an object stored inside the manager. The type to retrieve needs to
|
||||
/// be explicitly passed as a generic parameter or specified on the left hand side of the
|
||||
/// expression.
|
||||
pub fn get_ref<T: ManagedSystemObject>(&self, key: &ObjectId) -> Option<&T> {
|
||||
self.obj_map.get(key).and_then(|o| o.downcast_ref::<T>())
|
||||
}
|
||||
|
||||
/// Retrieve a mutable reference to an object stored inside the manager. The type to retrieve
|
||||
/// needs to be explicitly passed as a generic parameter or specified on the left hand side
|
||||
/// of the expression.
|
||||
pub fn get_mut<T: ManagedSystemObject>(&mut self, key: &ObjectId) -> Option<&mut T> {
|
||||
self.obj_map
|
||||
.get(key)
|
||||
.and_then(|o| o.as_ref().as_any().downcast_ref::<T>())
|
||||
.get_mut(key)
|
||||
.and_then(|o| o.downcast_mut::<T>())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::objects::{ManagedSystemObject, ObjectId, ObjectManager, SystemObject};
|
||||
use std::any::Any;
|
||||
use std::error::Error;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::thread;
|
||||
@ -148,10 +152,6 @@ mod tests {
|
||||
}
|
||||
|
||||
impl SystemObject for ExampleSysObj {
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn get_object_id(&self) -> &ObjectId {
|
||||
&self.id
|
||||
}
|
||||
@ -171,10 +171,6 @@ mod tests {
|
||||
}
|
||||
|
||||
impl SystemObject for OtherExampleObject {
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn get_object_id(&self) -> &ObjectId {
|
||||
&self.id
|
||||
}
|
||||
@ -199,7 +195,7 @@ mod tests {
|
||||
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);
|
||||
let obj_back_casted: Option<&ExampleSysObj> = obj_manager.get_ref(&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);
|
||||
@ -219,7 +215,7 @@ mod tests {
|
||||
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);
|
||||
let obj_back_casted: Option<&OtherExampleObject> = obj_manager.get_ref(&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"));
|
||||
@ -266,7 +262,7 @@ mod tests {
|
||||
let obj_man_0 = obj_manager.clone();
|
||||
let jh0 = thread::spawn(move || {
|
||||
let locked_man = obj_man_0.lock().expect("Mutex lock failed");
|
||||
let obj_back_casted: Option<&ExampleSysObj> = locked_man.get(&expl_obj_id);
|
||||
let obj_back_casted: Option<&ExampleSysObj> = locked_man.get_ref(&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);
|
||||
@ -276,7 +272,7 @@ mod tests {
|
||||
|
||||
let jh1 = thread::spawn(move || {
|
||||
let locked_man = obj_manager.lock().expect("Mutex lock failed");
|
||||
let obj_back_casted: Option<&OtherExampleObject> = locked_man.get(&second_obj_id);
|
||||
let obj_back_casted: Option<&OtherExampleObject> = locked_man.get_ref(&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"));
|
||||
|
@ -1,4 +1,5 @@
|
||||
//! TMTC module. Contains packet routing components with special support for CCSDS and ECSS packets.
|
||||
//! Telemetry and Telecommanding (TMTC) module. Contains packet routing components with special
|
||||
//! support for CCSDS and ECSS packets.
|
||||
use crate::error::{FsrcErrorRaw, FsrcGroupIds};
|
||||
use spacepackets::tc::PusTc;
|
||||
use spacepackets::SpHeader;
|
||||
@ -25,18 +26,31 @@ const FROM_BYTES_ZEROCOPY_ERROR: FsrcErrorRaw = FsrcErrorRaw::new(
|
||||
"FROM_BYTES_ZEROCOPY_ERROR",
|
||||
);
|
||||
|
||||
/// Generic trait for object which can receive any telecommands in form of a raw bytestream, with
|
||||
/// no assumptions about the received protocol.
|
||||
///
|
||||
/// This trait is implemented by both the [crate::tmtc::pus_distrib::PusDistributor] and the
|
||||
/// [crate::tmtc::ccsds_distrib::CcsdsDistributor] which allows to pass the respective packets in
|
||||
/// raw byte format into them.
|
||||
pub trait ReceivesTc {
|
||||
type Error;
|
||||
// TODO: Maybe it makes sense to return Result<(), Self::Error> here with Error being an associated
|
||||
// type..
|
||||
fn pass_tc(&mut self, tc_raw: &[u8]) -> Result<(), Self::Error>;
|
||||
}
|
||||
|
||||
/// Generic trait for object which can receive CCSDS space packets, for example ECSS PUS packets
|
||||
/// for CCSDS File Delivery Protocol (CFDP) packets.
|
||||
///
|
||||
/// This trait is implemented by both the [crate::tmtc::pus_distrib::PusDistributor] and the
|
||||
/// [crate::tmtc::ccsds_distrib::CcsdsDistributor] which allows
|
||||
/// to pass the respective packets in raw byte format or in CCSDS format into them.
|
||||
pub trait ReceivesCcsdsTc {
|
||||
type Error;
|
||||
fn pass_ccsds(&mut self, header: &SpHeader, tc_raw: &[u8]) -> Result<(), Self::Error>;
|
||||
}
|
||||
|
||||
/// Generic trait for objects which can receive ECSS PUS telecommands. This trait is
|
||||
/// implemented by the [crate::tmtc::pus_distrib::PusDistributor] objects to allow passing PUS TC
|
||||
/// packets into it.
|
||||
pub trait ReceivesEcssPusTc {
|
||||
type Error;
|
||||
fn pass_pus_tc(&mut self, header: &SpHeader, pus_tc: &PusTc) -> Result<(), Self::Error>;
|
||||
|
@ -25,6 +25,8 @@
|
||||
//! handler_call_count: u32
|
||||
//! }
|
||||
//!
|
||||
//! // This is a very simple possible service provider. It increments an internal call count field,
|
||||
//! // which is used to verify the handler was called
|
||||
//! impl PusServiceProvider for ConcretePusHandler {
|
||||
//! type Error = ();
|
||||
//! fn handle_pus_tc_packet(&mut self, service: u8, header: &SpHeader, pus_tc: &PusTc) -> Result<(), Self::Error> {
|
||||
@ -40,7 +42,7 @@
|
||||
//! };
|
||||
//! let mut pus_distributor = PusDistributor::new(Box::new(service_handler));
|
||||
//!
|
||||
//! // Create and pass PUS telecommand with a valid APID
|
||||
//! // Create and pass PUS ping telecommand with a valid APID
|
||||
//! let mut space_packet_header = SpHeader::tc(0x002, 0x34, 0).unwrap();
|
||||
//! let mut pus_tc = PusTc::new_simple(&mut space_packet_header, 17, 1, None, true);
|
||||
//! let mut test_buf: [u8; 32] = [0; 32];
|
||||
@ -51,7 +53,8 @@
|
||||
//!
|
||||
//! pus_distributor.pass_tc(tc_slice).expect("Passing PUS telecommand failed");
|
||||
//!
|
||||
//! // User helper function to retrieve concrete class
|
||||
//! // User helper function to retrieve concrete class. We check the call count here to verify
|
||||
//! // that the PUS ping telecommand was routed successfully.
|
||||
//! let concrete_handler_ref: &ConcretePusHandler = pus_distributor
|
||||
//! .service_provider_ref()
|
||||
//! .expect("Casting back to concrete type failed");
|
||||
@ -80,9 +83,7 @@ pub struct PusDistributor<E> {
|
||||
|
||||
impl<E> PusDistributor<E> {
|
||||
pub fn new(service_provider: Box<dyn PusServiceProvider<Error = E>>) -> Self {
|
||||
PusDistributor {
|
||||
service_provider
|
||||
}
|
||||
PusDistributor { service_provider }
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user