relm4/component/async/
connector.rs

1// Copyright 2021-2022 Aaron Erhardt <aaron.erhardt@t-online.de>
2// Copyright 2022 System76 <info@system76.com>
3// SPDX-License-Identifier: MIT or Apache-2.0
4
5use super::{
6    AsyncComponent, AsyncComponentController, AsyncController, stream::AsyncComponentStream,
7};
8use crate::{Receiver, Sender, ShutdownOnDrop};
9use std::fmt::{self, Debug};
10
11/// Contains the post-launch input sender and output receivers with the root widget.
12///
13/// The receiver can be separated from the `Fairing` by choosing a method for handling it.
14pub struct AsyncConnector<C: AsyncComponent> {
15    /// The widget that this component manages.
16    pub(super) widget: C::Root,
17
18    /// Used for emitting events to the component.
19    pub(super) sender: Sender<C::Input>,
20
21    /// The outputs being received by the component.
22    pub(super) receiver: Receiver<C::Output>,
23
24    /// Type used to destroy the async component when it's dropped.
25    pub(super) shutdown_on_drop: ShutdownOnDrop,
26}
27
28impl<C: AsyncComponent> AsyncConnector<C> {
29    /// Forwards output events to the designated sender.
30    pub fn forward<X: 'static, F: (Fn(C::Output) -> X) + 'static>(
31        self,
32        sender_: &Sender<X>,
33        transform: F,
34    ) -> AsyncController<C> {
35        let Self {
36            widget,
37            sender,
38            receiver,
39            shutdown_on_drop,
40        } = self;
41
42        crate::spawn_local(receiver.forward(sender_.clone(), transform));
43
44        AsyncController {
45            widget,
46            sender,
47            shutdown_on_drop,
48        }
49    }
50
51    /// Given a mutable closure, captures the receiver for handling.
52    pub fn connect_receiver<F: FnMut(&mut Sender<C::Input>, C::Output) + 'static>(
53        self,
54        mut func: F,
55    ) -> AsyncController<C> {
56        let Self {
57            widget,
58            sender,
59            receiver,
60            shutdown_on_drop,
61        } = self;
62
63        let mut sender_ = sender.clone();
64        crate::spawn_local(async move {
65            while let Some(event) = receiver.recv().await {
66                func(&mut sender_, event);
67            }
68        });
69
70        AsyncController {
71            widget,
72            sender,
73            shutdown_on_drop,
74        }
75    }
76
77    /// Ignore outputs from the component and finish the builder.
78    pub fn detach(self) -> AsyncController<C> {
79        let Self {
80            widget,
81            sender,
82            shutdown_on_drop,
83            ..
84        } = self;
85
86        AsyncController {
87            widget,
88            sender,
89            shutdown_on_drop,
90        }
91    }
92
93    /// Convert his type into a [`Stream`](futures::Stream) that yields output events
94    /// as futures.
95    pub fn into_stream(self) -> AsyncComponentStream<C> {
96        let Self {
97            receiver,
98            shutdown_on_drop,
99            ..
100        } = self;
101
102        AsyncComponentStream {
103            stream: receiver.into_stream(),
104            shutdown_on_drop,
105        }
106    }
107}
108
109impl<C: AsyncComponent> AsyncComponentController<C> for AsyncConnector<C> {
110    fn sender(&self) -> &Sender<C::Input> {
111        &self.sender
112    }
113
114    fn widget(&self) -> &C::Root {
115        &self.widget
116    }
117
118    fn detach_runtime(&mut self) {
119        self.shutdown_on_drop.deactivate();
120    }
121}
122
123impl<C> Debug for AsyncConnector<C>
124where
125    C: AsyncComponent + Debug,
126    C::Widgets: Debug,
127{
128    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
129        f.debug_struct("Connector")
130            .field("widget", &self.widget)
131            .field("sender", &self.sender)
132            .field("receiver", &self.receiver)
133            .field("shutdown_on_drop", &self.shutdown_on_drop)
134            .finish()
135    }
136}