Skip to content

Commit 80c3cba

Browse files
committed
feat: add protection for users
If get is used in a loop it's possible to not know that it's not doing anything useful anymore
1 parent 341f7fb commit 80c3cba

File tree

2 files changed

+49
-13
lines changed

2 files changed

+49
-13
lines changed

examples/loop_yield_data_state.rs

+16-11
Original file line numberDiff line numberDiff line change
@@ -35,17 +35,22 @@ async fn common_code() -> Result<(), Box<dyn std::error::Error>> {
3535
assert_eq!(status_code, &200);
3636
break;
3737
} else {
38-
state.get(|| {
39-
let req = client.get("http://httpbin.org/get");
40-
let response_handler = |resp: reqwest::Result<reqwest::Response>| async {
41-
resp.map(|resp| resp.status())
42-
.context("Request failed, got an error back")
43-
};
44-
let ui_notify = || {
45-
println!("Request Completed, this is where you would wake up your UI thread");
46-
};
47-
Awaiting(fetch_plus(req, response_handler, ui_notify))
48-
});
38+
let is_able_to_make_progress = state
39+
.get(|| {
40+
let req = client.get("http://httpbin.org/get");
41+
let response_handler = |resp: reqwest::Result<reqwest::Response>| async {
42+
resp.map(|resp| resp.status())
43+
.context("Request failed, got an error back")
44+
};
45+
let ui_notify = || {
46+
println!(
47+
"Request Completed, this is where you would wake up your UI thread"
48+
);
49+
};
50+
Awaiting(fetch_plus(req, response_handler, ui_notify))
51+
})
52+
.is_able_to_make_progress();
53+
assert!(is_able_to_make_progress);
4954
reqwest_cross::yield_now().await;
5055
}
5156
}

src/data_state.rs

+33-2
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@ pub enum DataStateError<E: ErrorBounds> {
2727
FromE(E),
2828
}
2929

30+
#[derive(Debug)]
31+
/// Provides a way to ensure the calling code knows if it is calling a function
32+
/// that cannot do anything useful anymore
33+
pub enum CanMakeProgress {
34+
AbleToMakeProgress,
35+
UnableToMakeProgress,
36+
}
37+
3038
/// Used to represent data that is pending being available
3139
#[derive(Debug)]
3240
pub struct Awaiting<T, E: ErrorBounds>(pub oneshot::Receiver<Result<T, E>>);
@@ -84,30 +92,35 @@ impl<T, E: ErrorBounds> DataState<T, E> {
8492
}
8593
}
8694

87-
/// Attempts to load the data.
95+
/// Attempts to load the data and returns if it is able to make progress.
8896
///
8997
/// Note: F needs to return `AwaitingType<T>` and not T because it needs to
9098
/// be able to be pending if T is not ready.
91-
pub fn get<F>(&mut self, fetch_fn: F)
99+
#[must_use]
100+
pub fn get<F>(&mut self, fetch_fn: F) -> CanMakeProgress
92101
where
93102
F: FnOnce() -> Awaiting<T, E>,
94103
{
95104
match self {
96105
DataState::None => {
97106
let rx = fetch_fn();
98107
*self = DataState::AwaitingResponse(rx);
108+
CanMakeProgress::AbleToMakeProgress
99109
}
100110
DataState::AwaitingResponse(rx) => {
101111
if let Some(new_state) = Self::await_data(rx) {
102112
*self = new_state;
103113
}
114+
CanMakeProgress::AbleToMakeProgress
104115
}
105116
DataState::Present(_data) => {
106117
// Does nothing data is already present
118+
CanMakeProgress::UnableToMakeProgress
107119
}
108120
DataState::Failed(_e) => {
109121
// Have no way to let the user know there is an error nothing we
110122
// can do here
123+
CanMakeProgress::UnableToMakeProgress
111124
}
112125
}
113126
}
@@ -184,3 +197,21 @@ impl From<String> for DataStateError<anyhow::Error> {
184197
anyhow!(value).into()
185198
}
186199
}
200+
201+
impl CanMakeProgress {
202+
/// Returns `true` if the can make progress is [`AbleToMakeProgress`].
203+
///
204+
/// [`AbleToMakeProgress`]: CanMakeProgress::AbleToMakeProgress
205+
#[must_use]
206+
pub fn is_able_to_make_progress(&self) -> bool {
207+
matches!(self, Self::AbleToMakeProgress)
208+
}
209+
210+
/// Returns `true` if the can make progress is [`UnableToMakeProgress`].
211+
///
212+
/// [`UnableToMakeProgress`]: CanMakeProgress::UnableToMakeProgress
213+
#[must_use]
214+
pub fn is_unable_to_make_progress(&self) -> bool {
215+
matches!(self, Self::UnableToMakeProgress)
216+
}
217+
}

0 commit comments

Comments
 (0)