use crate::message::MessageBytes; use crate::res::IFResult; use alloc::string::String; /// Some data that can be provided to the interface to send the message to a target. /// /// For IP this might be `IP:port`. /// Radio interface, for example, may not have the functionality of targeting, but that's fine pub(crate) type TargetingData = String; /// In an std environment we require that the interface can be send safely between threads #[cfg(not(feature = "std"))] pub trait InterfaceRequirements {} #[cfg(feature = "std")] pub trait InterfaceRequirements: Send + Sync {} /// An interface that can be used to pub trait Interface: InterfaceRequirements { /// Run one main loop iteration. /// On platforms that support concurrency, these functions will be run simultaneously for all interfaces. /// Most likely, this function will accept messages and save them somewhere internally to give out later in `Interface.receive()`. /// /// For systems that don't support concurrency, there can be only one interface in this function waits for a message (to avoid blocking). /// That's why it's necessary to check if it is the case for this interface, and it's done using function `Interface::has_blocking_main()` fn main_loop_iteration(&mut self) -> IFResult<()>; /// Check if `main_loop_iteration` stops execution and waits for a message fn has_blocking_main(&self) -> bool { false // hopefully... } /// Get some way of identification for this interface fn id(&self) -> &str; /// Send a message. If no `interface_data` is provided, we should consider it to be a broadcast. /// If, on the other hand, `interface_data` is not `None`, it should be used to send the message to the target. fn send( &mut self, message: &[u8], /*MessageBytes*/ interface_data: Option, ) -> IFResult<()>; /// Receive a message through this interface. Returns a result with an option of (message bytes, target). /// `None` means there is no message available at the time. /// The implementations of this function shouldn't wait for new messages, but fn receive(&mut self) -> IFResult>; } #[cfg(test)] pub mod test_interface { use crate::interface::{Interface, InterfaceRequirements, TargetingData}; use crate::message::MessageBytes; use crate::res::IFResult; use alloc::string::String; use alloc::vec::Vec; use alloc::vec; use alloc::string::ToString; use alloc::sync::Arc; use spin::Mutex; #[derive(Default)] pub struct SimpleTestInterface { messages: Vec<(Vec, TargetingData)>, } impl InterfaceRequirements for SimpleTestInterface {} impl Interface for SimpleTestInterface { fn main_loop_iteration(&mut self) -> IFResult<()> { Ok(()) } fn id(&self) -> &str { "test_interface" } fn send(&mut self, message: &[u8], interface_data: Option) -> IFResult<()> { self.messages .push((Vec::from(message), interface_data.unwrap_or_default())); Ok(()) } fn receive(&mut self) -> IFResult> { Ok(self.messages.pop()) } } pub type Storage = Vec<(Vec, TargetingData)>; #[derive(Default)] pub struct TestInterface { this_peer_id: String, storage: Arc>, messages: Vec<(Vec, TargetingData)>, } impl Interface for TestInterface { fn main_loop_iteration(&mut self) -> IFResult<()> { let mut storage_locked = self.storage.lock(); while let Some(i) = storage_locked .iter() .position(|msg| msg.1 == self.this_peer_id || msg.1.is_empty()) { self.messages.push(storage_locked.remove(i)); } Ok(()) } fn id(&self) -> &str { "test_interface" } fn send(&mut self, message: &[u8], target: Option) -> IFResult<()> { self .storage .lock() .push((Vec::from(message), target.unwrap_or_default())); Ok(()) } fn receive(&mut self) -> IFResult> { Ok(self.messages.pop()) } } impl InterfaceRequirements for TestInterface {} pub fn create_test_interfaces(n: usize) -> Vec { let storage_mutex = Arc::new(Mutex::new(vec![])); (0..n).map(|i| TestInterface { this_peer_id: i.to_string(), storage: storage_mutex.clone(), messages: vec![], }).collect() } #[test] fn test_test_interface() { let mut interfaces = create_test_interfaces(2); interfaces[0].send(b"123", Some("1".to_string())).unwrap(); interfaces[1].main_loop_iteration().unwrap(); assert_eq!(interfaces[1].receive().unwrap().unwrap().0.as_slice(), b"123"); } }