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}