main_loop_async/
data_state.rs1use anyhow::anyhow;
4use futures::channel::oneshot;
5use std::fmt::{Debug, Display};
6use thiserror::Error;
7use tracing::{error, warn};
8
9pub trait ErrorBounds: Display + Send + Sync + 'static + Debug {}
11impl<T: Display + Send + Sync + 'static + Debug> ErrorBounds for T {}
12
13#[derive(Error, Debug)]
14pub enum DataStateError<E: ErrorBounds> {
16 #[error("Task sender was dropped")]
18 SenderDropped(oneshot::Canceled),
19
20 #[error("Response received was an error: {0}")]
22 ErrorResponse(E),
23
24 #[error(transparent)]
26 FromE(E),
27}
28
29#[derive(Debug)]
30pub enum CanMakeProgress {
33 AbleToMakeProgress,
35
36 UnableToMakeProgress,
39}
40
41#[derive(Debug)]
43pub struct Awaiting<T, E: ErrorBounds>(pub oneshot::Receiver<Result<T, E>>);
44impl<T, E: ErrorBounds> From<oneshot::Receiver<Result<T, E>>> for Awaiting<T, E> {
45 fn from(value: oneshot::Receiver<Result<T, E>>) -> Self {
46 Self(value)
47 }
48}
49
50#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
53#[derive(Debug, Default)]
54pub enum DataState<T, E: ErrorBounds = anyhow::Error> {
55 #[default]
57 None,
58
59 #[cfg_attr(feature = "serde", serde(skip))]
60 AwaitingResponse(Awaiting<T, E>), Present(T),
65
66 #[cfg_attr(feature = "serde", serde(skip))]
67 Failed(DataStateError<E>),
69}
70
71impl<T, E: ErrorBounds> DataState<T, E> {
72 #[cfg(feature = "egui")]
73 pub fn egui_start_task<F, R>(&mut self, ui: &mut egui::Ui, f: F) -> CanMakeProgress
75 where
76 F: FnOnce() -> R,
77 R: Into<Awaiting<T, E>>,
78 {
79 let result = self.start_task(f);
80 if result.is_able_to_make_progress() {
81 ui.spinner();
82 }
83 result
84 }
85
86 #[must_use]
89 pub fn start_task<F, R>(&mut self, f: F) -> CanMakeProgress
90 where
91 F: FnOnce() -> R,
92 R: Into<Awaiting<T, E>>,
93 {
94 if self.is_none() {
95 *self = Self::AwaitingResponse(f().into());
96 CanMakeProgress::AbleToMakeProgress
97 } else {
98 debug_assert!(
99 false,
100 "No known good reason this path should be hit other than logic error"
101 );
102 CanMakeProgress::UnableToMakeProgress
103 }
104 }
105
106 pub fn poll(&mut self) -> &mut Self {
110 if let Self::AwaitingResponse(rx) = self
111 && let Some(new_state) = Self::await_data(rx)
112 {
113 *self = new_state;
114 }
115 self
116 }
117
118 #[cfg(feature = "egui")]
119 pub fn egui_poll_mut(
126 &mut self,
127 ui: &mut egui::Ui,
128 error_btn_text: Option<&str>,
129 ) -> Option<&mut T> {
130 match self {
131 Self::None => {}
132 Self::AwaitingResponse(_) => {
133 ui.spinner();
134 self.poll();
135 }
136 Self::Present(data) => {
137 return Some(data);
138 }
139 Self::Failed(e) => {
140 ui.colored_label(ui.visuals().error_fg_color, e.to_string());
141 if ui
142 .button(error_btn_text.unwrap_or("Clear Error Status"))
143 .clicked()
144 {
145 *self = Self::default();
146 }
147 }
148 }
149 None
150 }
151
152 #[cfg(feature = "egui")]
153 pub fn egui_poll(&mut self, ui: &mut egui::Ui, error_btn_text: Option<&str>) -> Option<&T> {
155 self.egui_poll_mut(ui, error_btn_text).map(|x| &*x)
156 }
157
158 pub fn await_data(rx: &mut Awaiting<T, E>) -> Option<Self> {
161 Some(match rx.0.try_recv() {
162 Ok(recv_opt) => match recv_opt {
163 Some(outcome_result) => match outcome_result {
164 Ok(data) => Self::Present(data),
165 Err(err_msg) => {
166 warn!(?err_msg, "Error response received instead of the data");
167 Self::Failed(DataStateError::ErrorResponse(err_msg))
168 }
169 },
170 None => {
171 return None;
172 }
173 },
174 Err(e) => {
175 error!("Error receiving on channel. Sender dropped.");
176 Self::Failed(DataStateError::SenderDropped(e))
177 }
178 })
179 }
180
181 pub fn present(&self) -> Option<&T> {
186 if let Self::Present(data) = self {
187 Some(data)
188 } else {
189 None
190 }
191 }
192
193 pub fn present_mut(&mut self) -> Option<&mut T> {
199 if let Self::Present(data) = self {
200 Some(data)
201 } else {
202 None
203 }
204 }
205
206 #[must_use]
210 pub fn is_present(&self) -> bool {
211 matches!(self, Self::Present(..))
212 }
213
214 #[must_use]
218 pub fn is_none(&self) -> bool {
219 matches!(self, Self::None)
220 }
221
222 #[must_use]
226 pub fn is_awaiting_response(&self) -> bool {
227 matches!(self, Self::AwaitingResponse(..))
228 }
229}
230
231impl<T, E: ErrorBounds> AsRef<Self> for DataState<T, E> {
232 fn as_ref(&self) -> &Self {
233 self
234 }
235}
236
237impl<T, E: ErrorBounds> AsMut<Self> for DataState<T, E> {
238 fn as_mut(&mut self) -> &mut Self {
239 self
240 }
241}
242
243impl<E: ErrorBounds> From<E> for DataStateError<E> {
244 fn from(value: E) -> Self {
245 Self::FromE(value)
246 }
247}
248
249impl From<&str> for DataStateError<anyhow::Error> {
250 fn from(value: &str) -> Self {
251 value.to_owned().into()
252 }
253}
254
255impl From<String> for DataStateError<anyhow::Error> {
256 fn from(value: String) -> Self {
257 anyhow!(value).into()
258 }
259}
260
261impl CanMakeProgress {
262 #[must_use]
266 pub fn is_able_to_make_progress(&self) -> bool {
267 matches!(self, Self::AbleToMakeProgress)
268 }
269
270 #[must_use]
274 pub fn is_unable_to_make_progress(&self) -> bool {
275 matches!(self, Self::UnableToMakeProgress)
276 }
277}