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}