relm4/component/
message_broker.rs

1use std::sync::Mutex;
2
3use crate::{Receiver, Sender};
4use once_cell::sync::Lazy;
5use std::fmt::Debug;
6
7#[derive(Debug)]
8/// A type that can be used in static variables to pass messages to components.
9///
10/// The primary use-case for this type is to communicate between components on different levels.
11///
12/// Imagine you have three components: A, B and C.
13/// A and B are children of the main application, but C is a child of B.
14/// If C wants to pass a message to A, it relies on B to forward that message to A.
15/// This is not great because B has nothing to do this message but has to implement additional
16/// logic only to pass the message through.
17/// [`MessageBroker`] allows you to use statics to remove this limitation.
18///
19/// # Note
20///
21/// [`MessageBroker`] will not forward any messages until you initialize them with
22/// [`ComponentBuilder::launch_with_broker()`](crate::ComponentBuilder::launch_with_broker()).
23///
24/// **Only initialize the message broker once!**
25///
26/// ```
27/// use relm4::{MessageBroker, Component};
28/// # type MyComponent = ();
29///
30/// static MY_COMPONENT: MessageBroker<()> = MessageBroker::new();
31///
32/// // Initialize the component and the message broker with `launch_with_broker`.
33/// let controller = MyComponent::builder().launch_with_broker((), &MY_COMPONENT).detach();
34/// ```
35pub struct MessageBroker<M: Debug> {
36    inner: Lazy<MessageBrokerInner<M>>,
37}
38
39impl<M: Debug> Default for MessageBroker<M> {
40    fn default() -> Self {
41        Self::new()
42    }
43}
44
45impl<M: Debug> MessageBroker<M> {
46    /// Creates a new [`MessageBroker`].
47    ///
48    /// The returned message broker will not forward messages until it's initialized.
49    #[must_use]
50    pub const fn new() -> Self {
51        let inner: Lazy<MessageBrokerInner<M>> = Lazy::new(|| MessageBrokerInner::<M>::new());
52        Self { inner }
53    }
54
55    /// Get the input sender of the component.
56    pub fn sender(&self) -> &Sender<M> {
57        &self.inner.sender
58    }
59
60    /// Send an input message to the component.
61    pub fn send(&self, input: M) {
62        self.inner.sender.send(input).unwrap();
63    }
64
65    pub(super) fn get_channel(&self) -> (Sender<M>, Option<Receiver<M>>) {
66        let inner = &self.inner;
67        (
68            inner.sender.clone(),
69            inner.input_receiver.lock().unwrap().take(),
70        )
71    }
72}
73
74struct MessageBrokerInner<M> {
75    sender: Sender<M>,
76    input_receiver: Mutex<Option<Receiver<M>>>,
77}
78
79impl<M> MessageBrokerInner<M> {
80    fn new() -> Self {
81        // Used for all events to be processed by this component's internal service.
82        let (sender, input_receiver) = crate::channel::<M>();
83        Self {
84            sender,
85            input_receiver: Mutex::new(Some(input_receiver)),
86        }
87    }
88}
89
90impl<M> Debug for MessageBrokerInner<M> {
91    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
92        f.debug_struct("MessageBrokerInner")
93            .field("sender", &self.sender)
94            .finish()
95    }
96}