Skip to main content

egui_async/egui/
bind_ext.rs

1//! Extension traits and helper functions for integrating `egui-async` logic ergonomically.
2
3use std::fmt::Debug;
4
5use super::widgets::ErrorPopup;
6use crate::bind::{Bind, MaybeSend, State};
7
8impl<T: 'static, E: Debug + 'static> Bind<T, E> {
9    /// Reads the data if available, otherwise shows an error popup if there was an error.
10    /// If there was an error, the popup will have a "Retry" button that will trigger the given future.
11    /// If the data is not available, returns `None`.
12    /// This does NOT automatically request the data if it is not available.
13    pub fn read_or_error<Fut>(&mut self, f: impl FnOnce() -> Fut, ui: &mut egui::Ui) -> Option<&T>
14    where
15        Fut: Future<Output = Result<T, E>> + MaybeSend + 'static,
16        T: MaybeSend,
17        E: MaybeSend,
18    {
19        self.poll();
20
21        if let Some(Err(e)) = &self.data {
22            if ErrorPopup::new(&format!("{e:?}")).show(ui.ctx()) {
23                self.request(f());
24            }
25            None
26        } else if let Some(Ok(data)) = self.data.as_ref() {
27            Some(data)
28        } else {
29            None
30        }
31    }
32
33    /// Reads the data mutably if available, otherwise shows an error popup if there was an error.
34    pub fn read_mut_or_error<Fut>(
35        &mut self,
36        f: impl FnOnce() -> Fut,
37        ui: &mut egui::Ui,
38    ) -> Option<&mut T>
39    where
40        Fut: Future<Output = Result<T, E>> + MaybeSend + 'static,
41        T: MaybeSend,
42        E: MaybeSend,
43    {
44        self.poll();
45
46        if let Some(Err(e)) = &self.data {
47            if ErrorPopup::new(&format!("{e:?}")).show(ui.ctx()) {
48                self.request(f());
49            }
50            None
51        } else if let Some(Ok(data)) = self.data.as_mut() {
52            Some(data)
53        } else {
54            None
55        }
56    }
57
58    /// Reads the data if available, otherwise requests it using the given future.
59    /// If there was an error, the popup will have a "Retry" button that will trigger the given future.
60    /// If the data is not available, returns `None`.
61    pub fn read_or_request_or_error<Fut>(
62        &mut self,
63        f: impl FnOnce() -> Fut,
64        ui: &mut egui::Ui,
65    ) -> Option<&T>
66    where
67        Fut: Future<Output = Result<T, E>> + MaybeSend + 'static,
68        T: MaybeSend,
69        E: MaybeSend,
70    {
71        self.poll();
72
73        if matches!(self.state, State::Idle) {
74            self.request(f());
75            None
76        } else if let Some(Err(e)) = &self.data {
77            if ErrorPopup::new(&format!("{e:?}")).show(ui.ctx()) {
78                self.request(f());
79            }
80            None
81        } else if let Some(Ok(data)) = self.data.as_ref() {
82            Some(data)
83        } else {
84            None
85        }
86    }
87
88    /// Reads the data mutably if available, otherwise requests it using the given future.
89    pub fn read_mut_or_request_or_error<Fut>(
90        &mut self,
91        f: impl FnOnce() -> Fut,
92        ui: &mut egui::Ui,
93    ) -> Option<&mut T>
94    where
95        Fut: Future<Output = Result<T, E>> + MaybeSend + 'static,
96        T: MaybeSend,
97        E: MaybeSend,
98    {
99        self.poll();
100
101        if matches!(self.state, State::Idle) {
102            self.request(f());
103            None
104        } else if let Some(Err(e)) = &self.data {
105            if ErrorPopup::new(&format!("{e:?}")).show(ui.ctx()) {
106                self.request(f());
107            }
108            None
109        } else if let Some(Ok(data)) = self.data.as_mut() {
110            Some(data)
111        } else {
112            None
113        }
114    }
115}