Function relm4::spawn_local
source · Expand description
Spawns a thread-local future on GLib’s executor, for non-Send
futures.
Examples found in repository?
src/component/sync/connector.rs (line 41)
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 65 66 67 68 69 70 71 72 73 74
pub fn forward<X: 'static, F: (Fn(C::Output) -> X) + 'static>(
self,
sender_: &Sender<X>,
transform: F,
) -> Controller<C> {
let Self {
state,
widget,
sender,
receiver,
} = self;
crate::spawn_local(receiver.forward(sender_.clone(), transform));
Controller {
state,
widget,
sender,
}
}
/// Given a mutable closure, captures the receiver for handling.
pub fn connect_receiver<F: FnMut(&mut Sender<C::Input>, C::Output) + 'static>(
self,
mut func: F,
) -> Controller<C> {
let Self {
state,
widget,
sender,
receiver,
} = self;
let mut sender_ = sender.clone();
crate::spawn_local(async move {
while let Some(event) = receiver.recv().await {
func(&mut sender_, event);
}
});
Controller {
state,
widget,
sender,
}
}
More examples
src/component/async/connector.rs (line 40)
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 65 66 67 68 69 70 71 72 73
pub fn forward<X: 'static, F: (Fn(C::Output) -> X) + 'static>(
self,
sender_: &Sender<X>,
transform: F,
) -> AsyncController<C> {
let Self {
widget,
sender,
receiver,
shutdown_on_drop,
} = self;
crate::spawn_local(receiver.forward(sender_.clone(), transform));
AsyncController {
widget,
sender,
shutdown_on_drop,
}
}
/// Given a mutable closure, captures the receiver for handling.
pub fn connect_receiver<F: FnMut(&mut Sender<C::Input>, C::Output) + 'static>(
self,
mut func: F,
) -> AsyncController<C> {
let Self {
widget,
sender,
receiver,
shutdown_on_drop,
} = self;
let mut sender_ = sender.clone();
crate::spawn_local(async move {
while let Some(event) = receiver.recv().await {
func(&mut sender_, event);
}
});
AsyncController {
widget,
sender,
shutdown_on_drop,
}
}
src/component/worker.rs (lines 199-203)
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
pub fn connect_receiver<F: FnMut(&mut Sender<W::Input>, W::Output) + 'static>(
self,
mut func: F,
) -> WorkerController<W> {
let Self {
sender,
receiver,
shutdown_on_drop,
} = self;
let mut sender_ = sender.clone();
crate::spawn_local(async move {
while let Some(event) = receiver.recv().await {
func(&mut sender_, event);
}
});
WorkerController {
sender,
shutdown_on_drop,
}
}
/// Forwards output events to the designated sender.
pub fn forward<X: 'static, F: (Fn(W::Output) -> X) + 'static>(
self,
sender: &Sender<X>,
transform: F,
) -> WorkerController<W> {
let Self {
sender: own_sender,
receiver,
shutdown_on_drop,
} = self;
crate::spawn_local(receiver.forward(sender.clone(), transform));
WorkerController {
sender: own_sender,
shutdown_on_drop,
}
}
src/factory/data_guard.rs (line 70)
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 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
pub(super) fn new<F, Fut, ShutdownFn>(
data: Box<C>,
widgets: Box<Widgets>,
shutdown_notifier: ShutdownSender,
output_sender: Sender<Output>,
f: F,
shutdown_fn: ShutdownFn,
) -> Self
where
Fut: Future<Output = ()> + 'static,
F: FnOnce(ManuallyDrop<Box<C>>, ManuallyDrop<Box<Widgets>>) -> Fut,
ShutdownFn: Fn(&mut C, &mut Widgets, Sender<Output>) + 'static,
{
// Duplicate the references to `data`
//
// # SAFETY
//
// This is safe because:
// 1. The first reference never calls the destructor (being wrapped in ManuallyDrop)
// 2. The first reference is always dropped first. This is guaranteed by types like
// `RuntimeDropper` and `FactoryHandle` that wrap the data and the runtime ID
// in a safe API that makes sure the runtime (and with it the first reference) is
// dropped before the second reference is dropped or extracted.
// 3. The second reference can only be extracted or dropped AFTER the first one
// was dropped. The second reference can then safely behave like a normal `Box<C>`.
//
// Unsoundness only occurs when data that was moved into the runtime is moved out on
// purpose. This would allow the first reference to outlive the second one, becoming
// a dangling pointer.
let (data, runtime_data) = unsafe {
let raw = Box::into_raw(data);
let data = Box::from_raw(raw);
let runtime_data = ManuallyDrop::new(Box::from_raw(raw));
(data, runtime_data)
};
let (widgets, runtime_widgets) = unsafe {
let raw = Box::into_raw(widgets);
let widgets = Box::from_raw(raw);
let runtime_widgets = ManuallyDrop::new(Box::from_raw(raw));
(widgets, runtime_widgets)
};
let future = f(runtime_data, runtime_widgets);
let rt_dropper = RuntimeDropper(Some(crate::spawn_local(future)));
let shutdown_fn = Box::new(shutdown_fn);
Self {
data,
widgets,
output_sender,
shutdown_notifier,
rt_dropper,
shutdown_fn,
}
}
src/factory/async/builder.rs (lines 80-88)
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
pub(super) fn launch<Transform>(
self,
index: &DynamicIndex,
returned_widget: <C::ParentWidget as FactoryView>::ReturnedWidget,
parent_sender: &Sender<C::ParentInput>,
transform: Transform,
) -> AsyncFactoryHandle<C>
where
Transform: Fn(C::Output) -> Option<C::ParentInput> + 'static,
{
let Self {
mut root_widget,
component_sender,
input_receiver,
output_receiver,
cmd_receiver,
shutdown_notifier,
init,
} = self;
let forward_sender = parent_sender.0.clone();
crate::spawn_local(async move {
while let Some(msg) = output_receiver.recv().await {
if let Some(new_msg) = transform(msg) {
if forward_sender.send(new_msg).is_err() {
break;
}
}
}
});
// Gets notifications when a component's model and view is updated externally.
let (notifier, notifier_receiver) = crate::channel();
let input_sender = component_sender.input_sender().clone();
let loading_widgets = C::init_loading_widgets(&mut root_widget);
let future_receiver = {
let index = index.clone();
let (future_sender, future_receiver) = crate::channel();
let future_data = FutureData {
shutdown_notifier,
index: index.clone(),
component_sender: component_sender.clone(),
root: root_widget.clone(),
returned_widget: returned_widget.clone(),
input_receiver,
cmd_receiver,
notifier_receiver,
};
crate::spawn_local(async move {
let data = C::init_model(init, &index, component_sender).await;
drop(loading_widgets);
let data_guard = future_data.start_runtime(data);
future_sender.send(data_guard).unwrap();
});
future_receiver
};
let data = AsyncData::new(future_receiver);
// Give back a type for controlling the component service.
AsyncFactoryHandle {
data,
root_widget,
returned_widget,
input: input_sender,
notifier,
}
}
src/factory/sync/builder.rs (lines 76-84)
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
pub(super) fn launch<Transform>(
self,
index: &DynamicIndex,
returned_widget: <C::ParentWidget as FactoryView>::ReturnedWidget,
parent_sender: &Sender<C::ParentInput>,
transform: Transform,
) -> FactoryHandle<C>
where
Transform: Fn(C::Output) -> Option<C::ParentInput> + 'static,
{
let Self {
mut data,
root_widget,
component_sender,
input_receiver,
output_receiver,
cmd_receiver,
shutdown_notifier,
} = self;
let forward_sender = parent_sender.0.clone();
crate::spawn_local(async move {
while let Some(msg) = output_receiver.recv().await {
if let Some(new_msg) = transform(msg) {
if forward_sender.send(new_msg).is_err() {
break;
}
}
}
});
// Gets notifications when a component's model and view is updated externally.
let (notifier, notifier_receiver) = crate::channel();
let widgets = Box::new(data.init_widgets(
index,
&root_widget,
&returned_widget,
component_sender.clone(),
));
let input_sender = component_sender.input_sender().clone();
let output_sender = component_sender.output_sender().clone();
// Spawns the component's service. It will receive both `Self::Input` and
// `Self::CommandOutput` messages. It will spawn commands as requested by
// updates, and send `Self::Output` messages externally.
let data = DataGuard::new(
data,
widgets,
shutdown_notifier,
output_sender,
|mut model, mut widgets| {
async move {
let mut notifier = GuardedReceiver::new(notifier_receiver);
let mut cmd = GuardedReceiver::new(cmd_receiver);
let mut input = GuardedReceiver::new(input_receiver);
loop {
futures::select!(
// Performs the model update, checking if the update requested a command.
// Runs that command asynchronously in the background using tokio.
message = input => {
let span = info_span!(
"update_with_view",
input=?message,
component=any::type_name::<C>(),
id=model.id(),
);
let _enter = span.enter();
model.update_with_view(&mut widgets, message, component_sender.clone());
}
// Handles responses from a command.
message = cmd => {
let span = info_span!(
"update_cmd_with_view",
cmd_output=?message,
component=any::type_name::<C>(),
id=model.id(),
);
let _enter = span.enter();
model.update_cmd_with_view(&mut widgets, message, component_sender.clone());
}
// Triggered when the model and view have been updated externally.
_ = notifier => {
model.update_view(&mut widgets, component_sender.clone());
}
);
}
}
},
C::shutdown,
);
// Give back a type for controlling the component service.
FactoryHandle {
data,
root_widget,
returned_widget,
input: input_sender,
notifier,
}
}