lazy_async_promise/
lib.rs1#![crate_name = "lazy_async_promise"]
2#![deny(missing_docs)]
18#![deny(deprecated)]
19#![deny(absolute_paths_not_starting_with_crate)]
20#![deny(unstable_features)]
21#![deny(unsafe_code)]
22
23extern crate core;
24
25use std::error::Error;
26use std::fmt::Debug;
27use std::future::Future;
28use std::ops::Deref;
29use std::pin::Pin;
30
31use tokio::sync::mpsc::Sender;
32
33#[doc(inline)]
34pub use immediatevalue::ImmediateValuePromise;
35pub use immediatevalue::ImmediateValueState;
36#[doc(inline)]
37pub use immediatevalueprogress::ProgressTrackedImValProm;
38pub use immediatevalueprogress::Status;
39pub use immediatevalueprogress::StringStatus;
40
41#[doc(inline)]
42pub use lazyvalue::LazyValuePromise;
43#[doc(inline)]
44pub use lazyvec::LazyVecPromise;
45
46mod immediatevalue;
47mod immediatevalueprogress;
48mod lazyvalue;
49mod lazyvec;
50
51pub struct BoxedSendError(pub Box<dyn Error + Send>);
53
54pub type FutureResult<T> = Result<T, BoxedSendError>;
56
57impl<E: Error + Send + 'static> From<E> for BoxedSendError {
58 fn from(e: E) -> Self {
59 BoxedSendError(Box::new(e))
60 }
61}
62
63impl Deref for BoxedSendError {
64 type Target = Box<dyn Error + Send>;
65
66 fn deref(&self) -> &Self::Target {
67 &self.0
68 }
69}
70
71pub trait DirectCacheAccess<T, E> {
73 fn get_value_mut(&mut self) -> Option<&mut T>;
75 fn get_value(&self) -> Option<&T>;
77 fn get_result(&self) -> Option<Result<&T, &E>>;
79 fn take_value(&mut self) -> Option<T>;
81 fn take_result(&mut self) -> Option<Result<T, E>>;
83}
84
85impl<T: Send + 'static, E: Send + 'static, A: DirectCacheAccess<T, E>> DirectCacheAccess<T, E>
87 for Option<A>
88{
89 fn get_value_mut(&mut self) -> Option<&mut T> {
90 self.as_mut().and_then(|inner| inner.get_value_mut())
91 }
92 fn get_value(&self) -> Option<&T> {
93 self.as_ref().and_then(|inner| inner.get_value())
94 }
95 fn get_result(&self) -> Option<Result<&T, &E>> {
96 self.as_ref().and_then(|inner| inner.get_result())
97 }
98 fn take_value(&mut self) -> Option<T> {
99 self.as_mut().and_then(|inner| inner.take_value())
100 }
101 fn take_result(&mut self) -> Option<Result<T, E>> {
102 self.as_mut().and_then(|inner| inner.take_result())
103 }
104}
105
106#[derive(Clone, Copy, PartialEq, Debug)]
108pub struct Progress(f64);
109
110impl<T: Into<f64>> From<T> for Progress {
111 fn from(t: T) -> Self {
112 Progress(t.into().clamp(0.0, 1.0))
113 }
114}
115
116pub mod api_macros {
118 pub use crate::send_data;
119 pub use crate::set_error;
120 pub use crate::set_finished;
121 pub use crate::set_progress;
122 pub use crate::unpack_result;
123 pub use crate::Progress;
124}
125
126impl Progress {
127 pub fn from_percent(percent: impl Into<f64>) -> Progress {
134 Self::from_fraction(percent, 100.)
135 }
136
137 pub fn from_fraction(numerator: impl Into<f64>, denominator: impl Into<f64>) -> Progress {
147 (numerator.into() / denominator.into()).into()
148 }
149
150 pub fn as_f32(&self) -> f32 {
152 self.0 as f32
153 }
154
155 pub fn as_f64(&self) -> f64 {
157 self.0
158 }
159}
160
161impl Default for Progress {
162 fn default() -> Self {
163 Progress(0.0)
164 }
165}
166
167impl Deref for Progress {
168 type Target = f64;
169 fn deref(&self) -> &Self::Target {
170 &self.0
171 }
172}
173
174#[derive(Clone, PartialEq, Debug)]
175pub enum DataState {
177 Uninitialized,
179 UpToDate,
181 Updating(Progress),
184 Error(String),
186}
187
188impl DataState {
189 pub fn get_progress(&self) -> Option<Progress> {
191 match &self {
192 DataState::Updating(progress) => Some(*progress),
193 _ => None,
194 }
195 }
196}
197
198#[derive(Debug)]
199pub enum Message<T: Debug> {
202 NewData(T),
204 StateChange(DataState),
206}
207
208pub trait Promise {
212 fn poll_state(&mut self) -> &DataState;
214 fn update(&mut self);
216}
217
218#[macro_export]
219macro_rules! unpack_result {
221 ( $result: expr, $sender: expr ) => {
222 match $result {
223 Ok(val) => val,
224 Err(e) => {
225 set_error!(format!("{}", e), $sender);
226 return;
227 }
228 }
229 };
230}
231
232#[macro_export]
233macro_rules! set_progress {
235 ($progress: expr, $sender: expr) => {
236 $sender
237 .send(Message::StateChange(DataState::Updating($progress)))
238 .await
239 .unwrap();
240 };
241}
242
243#[macro_export]
244macro_rules! set_error {
246 ($error: expr, $sender: expr) => {
247 $sender
248 .send(Message::StateChange(DataState::Error($error)))
249 .await
250 .unwrap();
251 };
252}
253
254#[macro_export]
255macro_rules! send_data {
257 ($data: expr, $sender: expr) => {
258 $sender.send(Message::NewData($data)).await.unwrap();
259 };
260}
261
262#[macro_export]
263macro_rules! set_finished {
265 ($sender: expr) => {
266 $sender
267 .send(Message::StateChange(DataState::UpToDate))
268 .await
269 .unwrap();
270 };
271}
272
273type BoxedFutureFactory<T> =
274 Box<dyn Fn(Sender<Message<T>>) -> Pin<Box<dyn Future<Output = ()> + Send + 'static>>>;
275
276fn box_future_factory<
277 T: Debug,
278 U: Fn(Sender<Message<T>>) -> Fut + 'static,
279 Fut: Future<Output = ()> + Send + 'static,
280>(
281 future_factory: U,
282) -> BoxedFutureFactory<T> {
283 Box::new(move |tx: Sender<Message<T>>| Box::pin(future_factory(tx)))
284}
285
286#[cfg(test)]
287mod test {
288 use super::*;
289
290 #[test]
291 fn progress_constructors() {
292 let half = Progress::from_percent(50);
293 assert_eq!(half.0, 0.5);
294 let half = Progress::from_fraction(1, 2);
295 assert_eq!(half.0, 0.5);
296 }
297
298 #[test]
299 fn progress_clamps() {
300 let minimum = Progress::from_percent(-50);
301 assert_eq!(minimum.as_f32(), 0.0);
302 let maximum = Progress::from_fraction(2, 1);
303 assert_eq!(maximum.as_f64(), 1.0);
304 let progress: Progress = 2.0.into();
305 assert_eq!(progress.as_f64(), 1.0);
306 }
307
308 #[test]
309 fn default_progress_is_start() {
310 assert_eq!(Progress::default().as_f64(), 0.0);
311 }
312}