You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
175 lines
5.8 KiB
175 lines
5.8 KiB
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<TargetingData>, |
|
) -> 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<Option<(MessageBytes, TargetingData /*interface data*/)>>; |
|
|
|
/// Dump the interface to string |
|
fn get_dump_data(&self) -> String; |
|
|
|
/// Create the interface from dumped data |
|
fn from_dump(data: String) -> IFResult<Self> where Self: Sized; |
|
} |
|
|
|
#[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::string::ToString; |
|
use alloc::sync::Arc; |
|
use alloc::vec; |
|
use alloc::vec::Vec; |
|
use spin::Mutex; |
|
|
|
#[derive(Default)] |
|
pub struct SimpleTestInterface { |
|
messages: Vec<(Vec<u8>, 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<TargetingData>) -> IFResult<()> { |
|
self.messages |
|
.push((Vec::from(message), interface_data.unwrap_or_default())); |
|
Ok(()) |
|
} |
|
|
|
fn receive(&mut self) -> IFResult<Option<(MessageBytes, TargetingData)>> { |
|
Ok(self.messages.pop()) |
|
} |
|
|
|
fn get_dump_data(&self) -> String { |
|
"".to_string() |
|
} |
|
|
|
fn from_dump(_data: String) -> IFResult<Self> { |
|
Ok(Default::default()) |
|
} |
|
} |
|
|
|
pub type Storage = Vec<(Vec<u8>, TargetingData)>; |
|
|
|
#[derive(Default)] |
|
pub struct TestInterface { |
|
this_peer_id: String, |
|
storage: Arc<Mutex<Storage>>, |
|
messages: Vec<(Vec<u8>, 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<TargetingData>) -> IFResult<()> { |
|
self.storage |
|
.lock() |
|
.push((Vec::from(message), target.unwrap_or_default())); |
|
Ok(()) |
|
} |
|
|
|
fn receive(&mut self) -> IFResult<Option<(MessageBytes, TargetingData)>> { |
|
Ok(self.messages.pop()) |
|
} |
|
|
|
fn get_dump_data(&self) -> String { |
|
"".to_string() |
|
} |
|
|
|
fn from_dump(_data: String) -> IFResult<Self> { |
|
Ok(TestInterface { |
|
this_peer_id: "".to_string(), |
|
storage: Arc::new(Default::default()), |
|
messages: vec![], |
|
}) |
|
} |
|
} |
|
|
|
impl InterfaceRequirements for TestInterface {} |
|
|
|
pub fn create_test_interfaces(n: usize) -> Vec<TestInterface> { |
|
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" |
|
); |
|
} |
|
}
|
|
|