introduce downcasting capabilities

This commit is contained in:
Robin Müller 2022-08-14 11:06:33 +02:00
parent 5de211cd40
commit 75bd86c802
No known key found for this signature in database
GPG Key ID: 71B58F8A3CDFA9AC
4 changed files with 202 additions and 20 deletions

8
fsrc-core/src/any.rs Normal file
View File

@ -0,0 +1,8 @@
use std::any::Any;
pub trait AsAny {
// I am not 100 % sure this is the best idea, but it allows downcasting the trait object
// to its original concrete type.
fn as_any(&self) -> &dyn Any;
fn as_mut_any(&mut self) -> &mut dyn Any;
}

View File

@ -1,4 +1,5 @@
//! # Core components of the Flight Software Rust Crate (FSRC) collection //! # Core components of the Flight Software Rust Crate (FSRC) collection
pub mod any;
pub mod error; pub mod error;
pub mod event_man; pub mod event_man;
pub mod events; pub mod events;

View File

@ -1,15 +1,16 @@
use crate::any::AsAny;
use crate::error::FsrcErrorHandler; use crate::error::FsrcErrorHandler;
use crate::tmtc::{ReceivesTc, FROM_BYTES_SLICE_TOO_SMALL_ERROR, FROM_BYTES_ZEROCOPY_ERROR}; use crate::tmtc::{ReceivesTc, FROM_BYTES_SLICE_TOO_SMALL_ERROR, FROM_BYTES_ZEROCOPY_ERROR};
use spacepackets::{CcsdsPacket, PacketError, SpHeader}; use spacepackets::{CcsdsPacket, PacketError, SpHeader};
pub trait ApidPacketHandler { pub trait ApidPacketHandler: AsAny {
fn valid_apids(&self) -> &'static [u16]; fn valid_apids(&self) -> &'static [u16];
fn handle_known_apid(&mut self, sp_header: &SpHeader, tc_raw: &[u8]); fn handle_known_apid(&mut self, sp_header: &SpHeader, tc_raw: &[u8]);
fn handle_unknown_apid(&mut self, sp_header: &SpHeader, tc_raw: &[u8]); fn handle_unknown_apid(&mut self, sp_header: &SpHeader, tc_raw: &[u8]);
} }
pub struct CcsdsDistributor { pub struct CcsdsDistributor {
apid_handler: Box<dyn ApidPacketHandler>, pub apid_handler: Box<dyn ApidPacketHandler>,
error_handler: Box<dyn FsrcErrorHandler>, error_handler: Box<dyn FsrcErrorHandler>,
} }
@ -66,16 +67,32 @@ pub(crate) mod tests {
use crate::tmtc::ccsds_distrib::{ApidPacketHandler, CcsdsDistributor}; use crate::tmtc::ccsds_distrib::{ApidPacketHandler, CcsdsDistributor};
use spacepackets::tc::PusTc; use spacepackets::tc::PusTc;
use spacepackets::CcsdsPacket; use spacepackets::CcsdsPacket;
use std::any::Any;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
#[derive(Default)] pub struct BasicApidHandlerSharedQueue {
pub struct BasicApidHandler {
pub known_packet_queue: Arc<Mutex<VecDeque<(u16, Vec<u8>)>>>, pub known_packet_queue: Arc<Mutex<VecDeque<(u16, Vec<u8>)>>>,
pub unknown_packet_queue: Arc<Mutex<VecDeque<(u16, Vec<u8>)>>>, pub unknown_packet_queue: Arc<Mutex<VecDeque<(u16, Vec<u8>)>>>,
} }
impl ApidPacketHandler for BasicApidHandler { #[derive(Default)]
pub struct BasicApidHandlerOwnedQueue {
pub known_packet_queue: VecDeque<(u16, Vec<u8>)>,
pub unknown_packet_queue: VecDeque<(u16, Vec<u8>)>,
}
impl AsAny for BasicApidHandlerSharedQueue {
fn as_any(&self) -> &dyn Any {
self
}
fn as_mut_any(&mut self) -> &mut dyn Any {
self
}
}
impl ApidPacketHandler for BasicApidHandlerSharedQueue {
fn valid_apids(&self) -> &'static [u16] { fn valid_apids(&self) -> &'static [u16] {
&[0x000, 0x002] &[0x000, 0x002]
} }
@ -99,11 +116,39 @@ pub(crate) mod tests {
} }
} }
impl AsAny for BasicApidHandlerOwnedQueue {
fn as_any(&self) -> &dyn Any {
self
}
fn as_mut_any(&mut self) -> &mut dyn Any {
self
}
}
impl ApidPacketHandler for BasicApidHandlerOwnedQueue {
fn valid_apids(&self) -> &'static [u16] {
&[0x000, 0x002]
}
fn handle_known_apid(&mut self, sp_header: &SpHeader, tc_raw: &[u8]) {
let mut vec = Vec::new();
vec.extend_from_slice(tc_raw);
self.known_packet_queue.push_back((sp_header.apid(), vec));
}
fn handle_unknown_apid(&mut self, sp_header: &SpHeader, tc_raw: &[u8]) {
let mut vec = Vec::new();
vec.extend_from_slice(tc_raw);
self.unknown_packet_queue.push_back((sp_header.apid(), vec));
}
}
#[test] #[test]
fn test_distribs_known_apid() { fn test_distribs_known_apid() {
let known_packet_queue = Arc::new(Mutex::default()); let known_packet_queue = Arc::new(Mutex::default());
let unknown_packet_queue = Arc::new(Mutex::default()); let unknown_packet_queue = Arc::new(Mutex::default());
let apid_handler = BasicApidHandler { let apid_handler = BasicApidHandlerSharedQueue {
known_packet_queue: known_packet_queue.clone(), known_packet_queue: known_packet_queue.clone(),
unknown_packet_queue: unknown_packet_queue.clone(), unknown_packet_queue: unknown_packet_queue.clone(),
}; };
@ -129,7 +174,7 @@ pub(crate) mod tests {
fn test_distribs_unknown_apid() { fn test_distribs_unknown_apid() {
let known_packet_queue = Arc::new(Mutex::default()); let known_packet_queue = Arc::new(Mutex::default());
let unknown_packet_queue = Arc::new(Mutex::default()); let unknown_packet_queue = Arc::new(Mutex::default());
let apid_handler = BasicApidHandler { let apid_handler = BasicApidHandlerSharedQueue {
known_packet_queue: known_packet_queue.clone(), known_packet_queue: known_packet_queue.clone(),
unknown_packet_queue: unknown_packet_queue.clone(), unknown_packet_queue: unknown_packet_queue.clone(),
}; };

View File

@ -1,15 +1,16 @@
use crate::any::AsAny;
use crate::error::FsrcErrorHandler; use crate::error::FsrcErrorHandler;
use crate::tmtc::{ReceivesCcsdsTc, ReceivesTc}; use crate::tmtc::{ReceivesCcsdsTc, ReceivesTc};
use spacepackets::ecss::{PusError, PusPacket}; use spacepackets::ecss::{PusError, PusPacket};
use spacepackets::tc::PusTc; use spacepackets::tc::PusTc;
use spacepackets::{CcsdsPacket, PacketError, SpHeader}; use spacepackets::{CcsdsPacket, PacketError, SpHeader};
pub trait PusServiceProvider { pub trait PusServiceProvider: AsAny {
fn handle_pus_tc_packet(&mut self, service: u8, apid: u16, pus_tc: &PusTc); fn handle_pus_tc_packet(&mut self, service: u8, apid: u16, pus_tc: &PusTc);
} }
pub struct PusDistributor { pub struct PusDistributor {
service_provider: Box<dyn PusServiceProvider>, pub service_provider: Box<dyn PusServiceProvider>,
error_handler: Box<dyn FsrcErrorHandler>, error_handler: Box<dyn FsrcErrorHandler>,
} }
@ -49,17 +50,35 @@ impl ReceivesCcsdsTc for PusDistributor {
mod tests { mod tests {
use super::*; use super::*;
use crate::error::SimpleStdErrorHandler; use crate::error::SimpleStdErrorHandler;
use crate::tmtc::ccsds_distrib::tests::BasicApidHandler; use crate::tmtc::ccsds_distrib::tests::{
BasicApidHandlerOwnedQueue, BasicApidHandlerSharedQueue,
};
use crate::tmtc::ccsds_distrib::{ApidPacketHandler, CcsdsDistributor}; use crate::tmtc::ccsds_distrib::{ApidPacketHandler, CcsdsDistributor};
use spacepackets::tc::PusTc; use spacepackets::tc::PusTc;
use std::any::Any;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
struct PusHandler { struct PusHandlerSharedQueue {
pus_queue: Arc<Mutex<VecDeque<(u8, u16, Vec<u8>)>>>, pub pus_queue: Arc<Mutex<VecDeque<(u8, u16, Vec<u8>)>>>,
} }
impl PusServiceProvider for PusHandler { #[derive(Default)]
struct PusHandlerOwnedQueue {
pub pus_queue: VecDeque<(u8, u16, Vec<u8>)>,
}
impl AsAny for PusHandlerSharedQueue {
fn as_any(&self) -> &dyn Any {
self
}
fn as_mut_any(&mut self) -> &mut dyn Any {
self
}
}
impl PusServiceProvider for PusHandlerSharedQueue {
fn handle_pus_tc_packet(&mut self, service: u8, apid: u16, pus_tc: &PusTc) { fn handle_pus_tc_packet(&mut self, service: u8, apid: u16, pus_tc: &PusTc) {
let mut vec: Vec<u8> = Vec::new(); let mut vec: Vec<u8> = Vec::new();
pus_tc pus_tc
@ -72,12 +91,42 @@ mod tests {
} }
} }
struct ApidHandler { impl AsAny for PusHandlerOwnedQueue {
pus_distrib: PusDistributor, fn as_any(&self) -> &dyn Any {
handler_base: BasicApidHandler, self
}
fn as_mut_any(&mut self) -> &mut dyn Any {
self
}
} }
impl ApidPacketHandler for ApidHandler { impl PusServiceProvider for PusHandlerOwnedQueue {
fn handle_pus_tc_packet(&mut self, service: u8, apid: u16, pus_tc: &PusTc) {
let mut vec: Vec<u8> = Vec::new();
pus_tc
.append_to_vec(&mut vec)
.expect("Appending raw PUS TC to vector failed");
self.pus_queue.push_back((service, apid, vec));
}
}
struct ApidHandlerShared {
pub pus_distrib: PusDistributor,
handler_base: BasicApidHandlerSharedQueue,
}
impl AsAny for ApidHandlerShared {
fn as_any(&self) -> &dyn Any {
self
}
fn as_mut_any(&mut self) -> &mut dyn Any {
self
}
}
impl ApidPacketHandler for ApidHandlerShared {
fn valid_apids(&self) -> &'static [u16] { fn valid_apids(&self) -> &'static [u16] {
&[0x000, 0x002] &[0x000, 0x002]
} }
@ -94,15 +143,46 @@ mod tests {
} }
} }
struct ApidHandlerOwned {
pub pus_distrib: PusDistributor,
handler_base: BasicApidHandlerOwnedQueue,
}
impl AsAny for ApidHandlerOwned {
fn as_any(&self) -> &dyn Any {
self
}
fn as_mut_any(&mut self) -> &mut dyn Any {
self
}
}
impl ApidPacketHandler for ApidHandlerOwned {
fn valid_apids(&self) -> &'static [u16] {
&[0x000, 0x002]
}
fn handle_known_apid(&mut self, sp_header: &SpHeader, tc_raw: &[u8]) {
self.handler_base.handle_known_apid(&sp_header, tc_raw);
self.pus_distrib
.pass_ccsds(&sp_header, tc_raw)
.expect("Passing PUS packet failed");
}
fn handle_unknown_apid(&mut self, sp_header: &SpHeader, tc_raw: &[u8]) {
self.handler_base.handle_unknown_apid(&sp_header, tc_raw);
}
}
#[test] #[test]
fn test_pus_distribution() { fn test_pus_distribution() {
let known_packet_queue = Arc::new(Mutex::default()); let known_packet_queue = Arc::new(Mutex::default());
let unknown_packet_queue = Arc::new(Mutex::default()); let unknown_packet_queue = Arc::new(Mutex::default());
let pus_queue = Arc::new(Mutex::default()); let pus_queue = Arc::new(Mutex::default());
let pus_handler = PusHandler { let pus_handler = PusHandlerSharedQueue {
pus_queue: pus_queue.clone(), pus_queue: pus_queue.clone(),
}; };
let handler_base = BasicApidHandler { let handler_base = BasicApidHandlerSharedQueue {
known_packet_queue: known_packet_queue.clone(), known_packet_queue: known_packet_queue.clone(),
unknown_packet_queue: unknown_packet_queue.clone(), unknown_packet_queue: unknown_packet_queue.clone(),
}; };
@ -113,7 +193,7 @@ mod tests {
error_handler: Box::new(error_handler), error_handler: Box::new(error_handler),
}; };
let apid_handler = ApidHandler { let apid_handler = ApidHandlerShared {
pus_distrib, pus_distrib,
handler_base, handler_base,
}; };
@ -141,4 +221,52 @@ mod tests {
assert_eq!(apid, 0x002); assert_eq!(apid, 0x002);
assert_eq!(tc_raw, tc_slice); assert_eq!(tc_raw, tc_slice);
} }
#[test]
fn test_as_any_cast() {
let pus_handler = PusHandlerOwnedQueue::default();
let handler_base = BasicApidHandlerOwnedQueue::default();
let error_handler = SimpleStdErrorHandler {};
let pus_distrib = PusDistributor {
service_provider: Box::new(pus_handler),
error_handler: Box::new(error_handler),
};
let apid_handler = ApidHandlerOwned {
pus_distrib,
handler_base,
};
let mut ccsds_distrib =
CcsdsDistributor::new(Box::new(apid_handler), Box::new(error_handler));
let mut sph = SpHeader::tc(0x002, 0x34, 0).unwrap();
let pus_tc = PusTc::new_simple(&mut sph, 17, 1, None, true);
let mut test_buf: [u8; 32] = [0; 32];
let size = pus_tc
.write_to(test_buf.as_mut_slice())
.expect("Error writing TC to buffer");
let tc_slice = &test_buf[0..size];
ccsds_distrib.pass_tc(tc_slice);
let apid_handler_casted_back: &mut ApidHandlerOwned = ccsds_distrib
.apid_handler
.as_mut_any()
.downcast_mut::<ApidHandlerOwned>()
.expect("Cast to concrete type ApidHandler failed");
assert!(!apid_handler_casted_back
.handler_base
.known_packet_queue
.is_empty());
let handler_casted_back: &mut PusHandlerOwnedQueue = apid_handler_casted_back
.pus_distrib
.service_provider
.as_mut_any()
.downcast_mut::<PusHandlerOwnedQueue>()
.expect("Cast to concrete type PusHandler failed");
assert!(!handler_casted_back.pus_queue.is_empty());
let (service, apid, packet_raw) = handler_casted_back.pus_queue.pop_front().unwrap();
assert_eq!(service, 17);
assert_eq!(apid, 0x002);
assert_eq!(packet_raw.as_slice(), tc_slice);
}
} }