1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
use crossbeam::channel::{Receiver, Sender};
use std::error::Error;

pub struct Bus<T>
where
    T: Copy,
{
    subscriptions: Vec<(Box<dyn FnMut(T) -> bool + 'static>, Sender<T>)>,
}

impl<T> Bus<T>
where
    T: Copy,
{
    pub fn new() -> Self {
        Bus {
            subscriptions: vec![],
        }
    }

    pub fn send(&mut self, message: T) -> Result<(), crossbeam::channel::SendError<T>> {
        for v in self.subscriptions.iter_mut() {
            if v.0(message) {
                match v.1.send(message) {
                    Ok(()) => (),
                    Err(e) => {
                        return Err(e);
                    }
                }
            }
        }

        return Ok(());
    }

    pub fn subscribe(&mut self, guard: impl FnMut(T) -> bool + 'static) -> Receiver<T> {
        let (sender, receiver) = crossbeam_channel::unbounded();
        self.subscriptions.push((Box::new(guard), sender));
        return receiver;
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn send_message() {
        let mut test_bus: Bus<&[u8]> = Bus::new();
        assert_eq!(test_bus.send("test".as_bytes()), Ok(()));
    }

    #[test]
    fn send_message_and_receive() {
        let mut test_bus: Bus<&[u8]> = Bus::new();
        let receiver = test_bus.subscribe(|x| return x == "test".as_bytes());
        match test_bus.send("test".as_bytes()) {
            Ok(()) => {
                assert_eq!(receiver.recv().unwrap(), "test".as_bytes());
            }
            Err(_) => return,
        }
    }
}