yield_progress/builder.rs
1use core::future::Future;
2
3use alloc::boxed::Box;
4use alloc::sync::Arc;
5
6use crate::{BoxFuture, ProgressInfo, YieldInfo, YieldProgress, Yielding, basic_yield_now};
7
8/// Builder for creating root [`YieldProgress`] instances.
9///
10/// # Example
11///
12/// ```
13/// # struct Pb;
14/// # impl Pb { fn set_value(&self, _value: f32) {} }
15/// # let some_progress_bar = Pb;
16/// let progress = yield_progress::Builder::new()
17/// .yield_using(|_| tokio::task::yield_now())
18/// .progress_using(move |info| {
19/// some_progress_bar.set_value(info.fraction());
20/// })
21/// .build();
22/// ```
23#[derive(Clone)]
24#[must_use]
25pub struct Builder {
26 yielding: Arc<Yielding<crate::YieldFn>>,
27 /// public to allow overriding the API `Sync` requirement
28 pub(crate) progressor: Arc<crate::ProgressFn>,
29}
30
31impl Builder {
32 /// Constructs a [`Builder`].
33 ///
34 /// The default values are:
35 ///
36 /// * The yield function is [`basic_yield_now`].
37 /// * The progress function does nothing.
38 ///
39 /// The call site of this function is considered to be the yield point preceding the first actual
40 /// yield point.
41 #[track_caller]
42 pub fn new() -> Builder {
43 Builder {
44 yielding: Arc::new(Yielding {
45 yielder: move |_info: &YieldInfo<'_>| -> BoxFuture<'static, ()> {
46 Box::pin(basic_yield_now())
47 },
48 #[cfg(feature = "log_hiccups")]
49 state: std::sync::Mutex::new(crate::YieldState {
50 last_finished_yielding: web_time::Instant::now(),
51 last_yield_location: core::panic::Location::caller(),
52 last_yield_label: None,
53 }),
54 }),
55 progressor: Arc::new(|_| {}),
56 }
57 }
58
59 /// Construct a new [`YieldProgress`] using the behaviors specified by this builder.
60 pub fn build(self) -> YieldProgress {
61 let Self {
62 yielding,
63 progressor,
64 } = self;
65
66 YieldProgress {
67 start: 0.0,
68 end: 1.0,
69 label: None,
70 yielding,
71 progressor,
72 }
73 }
74
75 /// Set the function which will be called in order to yield.
76 ///
77 /// See [`basic_yield_now()`] for the default implementation used if this is not not set, and
78 /// some information about what you might want to pass here instead.
79 #[allow(clippy::missing_panics_doc)] // internal, can't happen
80 pub fn yield_using<Y, YFut>(mut self, function: Y) -> Self
81 where
82 Y: for<'a> Fn(&'a YieldInfo<'a>) -> YFut + Send + Sync + 'static,
83 YFut: Future<Output = ()> + Send + 'static,
84 {
85 let new_yielding = Arc::new(Yielding {
86 yielder: move |info: &YieldInfo<'_>| -> BoxFuture<'static, ()> {
87 Box::pin(function(info))
88 },
89 #[cfg(feature = "log_hiccups")]
90 state: std::sync::Mutex::new(self.yielding.state.lock().unwrap().clone()),
91 });
92 self.yielding = new_yielding;
93 self
94 }
95
96 /// Internal version of `yield_using` which takes an already boxed function and yielding state.
97 #[cfg_attr(not(feature = "sync"), allow(dead_code))]
98 pub(crate) fn yielding_internal(mut self, new_yielding: crate::BoxYielding) -> Self {
99 self.yielding = new_yielding;
100 self
101 }
102
103 /// Set the function which will be called in order to report progress.
104 ///
105 /// If this is called more than once, the previous function will be discarded (there is no list
106 /// of callbacks). If this is not called, the default function used does nothing.
107 pub fn progress_using<P>(mut self, function: P) -> Self
108 where
109 P: for<'a> Fn(&'a ProgressInfo<'a>) + Send + Sync + 'static,
110 {
111 self.progressor = Arc::new(function);
112 self
113 }
114}
115
116impl Default for Builder {
117 fn default() -> Self {
118 Self::new()
119 }
120}