perspective_viewer/utils/scope.rs
1// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
2// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
3// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
4// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
5// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
6// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
7// ┃ Copyright (c) 2017, the Perspective Authors. ┃
8// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
9// ┃ This file is part of the Perspective library, distributed under the terms ┃
10// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
11// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
12
13use extend::ext;
14use futures::channel::oneshot::*;
15use perspective_js::utils::ApiResult;
16use yew::html::Scope;
17use yew::prelude::*;
18
19#[ext]
20pub impl<T> Scope<T>
21where
22 T: Component,
23{
24 /// Send a message with a callback, then suspend until the callback is
25 /// invoked.
26 fn send_message_async<F, U>(&self, f: F) -> Receiver<U>
27 where
28 F: FnOnce(Sender<U>) -> T::Message,
29 {
30 let (sender, receiver) = channel::<U>();
31 self.send_message(f(sender));
32 receiver
33 }
34}
35
36#[ext]
37pub(crate) impl<T> Callback<Sender<T>>
38where
39 T: 'static,
40{
41 /// This is "safe" because `emit()` is not called synchronously. Normally
42 /// we want this to minimize the async by doing as much work synchronous
43 /// as possible (see `send_message_async()` e.g.), but this method calls
44 /// `Yew` which _never_ wants to be called synchronously.
45 ///
46 /// TODO Need test coverage for this - error behavior is that presize/render
47 /// blocking calls are out-of-order, e.g. toggle config `presize()` call.
48 /// Engineering the test to capture this faulty behavior may be difficult
49 async fn emit_async_safe(&self) -> ApiResult<T> {
50 let (sender, receiver) = channel::<T>();
51 self.emit(sender);
52 Ok(receiver.await?)
53 }
54}