@@ -37,6 +37,11 @@ pub enum CanMakeProgress {
37
37
/// Used to represent data that is pending being available
38
38
#[ derive( Debug ) ]
39
39
pub struct Awaiting < T , E : ErrorBounds > ( pub oneshot:: Receiver < Result < T , E > > ) ;
40
+ impl < T , E : ErrorBounds > From < oneshot:: Receiver < Result < T , E > > > for Awaiting < T , E > {
41
+ fn from ( value : oneshot:: Receiver < Result < T , E > > ) -> Self {
42
+ Self ( value)
43
+ }
44
+ }
40
45
41
46
/// Used to store a type that is not always available and we need to keep
42
47
/// polling it to get it ready
@@ -57,9 +62,10 @@ impl<T, E: ErrorBounds> DataState<T, E> {
57
62
#[ cfg( feature = "egui" ) ]
58
63
/// Calls [Self::start_request] and adds a spinner if progress can be made
59
64
#[ must_use]
60
- pub fn egui_start_request < F > ( & mut self , ui : & mut egui:: Ui , fetch_fn : F ) -> CanMakeProgress
65
+ pub fn egui_start_request < F , R > ( & mut self , ui : & mut egui:: Ui , fetch_fn : F ) -> CanMakeProgress
61
66
where
62
- F : FnOnce ( ) -> Awaiting < T , E > ,
67
+ F : FnOnce ( ) -> R ,
68
+ R : Into < Awaiting < T , E > > ,
63
69
{
64
70
let result = self . start_request ( fetch_fn) ;
65
71
if result. is_able_to_make_progress ( ) {
@@ -69,97 +75,77 @@ impl<T, E: ErrorBounds> DataState<T, E> {
69
75
}
70
76
71
77
/// Starts a new request. Only intended to be on [Self::None] and if state
72
- /// is any other value it returns
73
- /// [CanMakeProgress::UnableToMakeProgress]
78
+ /// is any other value it returns [CanMakeProgress::UnableToMakeProgress]
74
79
#[ must_use]
75
- pub fn start_request < F > ( & mut self , fetch_fn : F ) -> CanMakeProgress
80
+ pub fn start_request < F , R > ( & mut self , fetch_fn : F ) -> CanMakeProgress
76
81
where
77
- F : FnOnce ( ) -> Awaiting < T , E > ,
82
+ F : FnOnce ( ) -> R ,
83
+ R : Into < Awaiting < T , E > > ,
78
84
{
79
85
if self . is_none ( ) {
80
- let result = self . get ( fetch_fn) ;
81
- assert ! ( result. is_able_to_make_progress( ) ) ;
82
- result
86
+ * self = DataState :: AwaitingResponse ( fetch_fn ( ) . into ( ) ) ;
87
+ CanMakeProgress :: AbleToMakeProgress
83
88
} else {
89
+ debug_assert ! (
90
+ false ,
91
+ "No known good reason this path should be hit other than logic error"
92
+ ) ;
84
93
CanMakeProgress :: UnableToMakeProgress
85
94
}
86
95
}
87
96
97
+ /// Convenience method that will try to make progress if in
98
+ /// [Self::AwaitingResponse] and does nothing otherwise. Returns a reference
99
+ /// to self for chaining
100
+ pub fn poll ( & mut self ) -> & mut Self {
101
+ if let DataState :: AwaitingResponse ( rx) = self {
102
+ if let Some ( new_state) = Self :: await_data ( rx) {
103
+ * self = new_state;
104
+ }
105
+ }
106
+ self
107
+ }
108
+
88
109
#[ cfg( feature = "egui" ) ]
89
- /// Attempts to load the data and displays appropriate UI if applicable.
90
- /// Some branches lead to no UI being displayed, in particular when the data
91
- /// or an error is received (On the expectation it will show next frame).
92
- /// When in an error state the error messages will show as applicable.
93
- /// If called an already has data present this function does nothing and
94
- /// returns [CanMakeProgress::UnableToMakeProgress]
110
+ /// Meant to be a simple method to just provide the data if it's ready or
111
+ /// help with UI and polling to get it ready if it's not.
95
112
///
96
- /// If a `retry_msg ` is provided then it overrides the default
113
+ /// WARNING: Does nothing if `self ` is [Self::None]
97
114
///
98
- /// Note see [`Self::get`] for more info.
115
+ /// If a `error_btn_text` is provided then it overrides the default
99
116
#[ must_use]
100
- pub fn egui_get < F > (
117
+ pub fn egui_poll_mut (
101
118
& mut self ,
102
119
ui : & mut egui:: Ui ,
103
- retry_msg : Option < & str > ,
104
- fetch_fn : F ,
105
- ) -> CanMakeProgress
106
- where
107
- F : FnOnce ( ) -> Awaiting < T , E > ,
108
- {
120
+ error_btn_text : Option < & str > ,
121
+ ) -> Option < & mut T > {
109
122
match self {
110
- DataState :: None => {
111
- ui. spinner ( ) ;
112
- self . get ( fetch_fn)
113
- }
123
+ DataState :: None => { }
114
124
DataState :: AwaitingResponse ( _) => {
115
125
ui. spinner ( ) ;
116
- self . get ( fetch_fn )
126
+ self . poll ( ) ;
117
127
}
118
- DataState :: Present ( _data) => {
119
- // Does nothing as data is already present
120
- CanMakeProgress :: UnableToMakeProgress
128
+ DataState :: Present ( data) => {
129
+ return Some ( data) ;
121
130
}
122
131
DataState :: Failed ( e) => {
123
132
ui. colored_label ( ui. visuals ( ) . error_fg_color , e. to_string ( ) ) ;
124
- if ui. button ( retry_msg. unwrap_or ( "Retry Request" ) ) . clicked ( ) {
133
+ if ui
134
+ . button ( error_btn_text. unwrap_or ( "Clear Error Status" ) )
135
+ . clicked ( )
136
+ {
125
137
* self = DataState :: default ( ) ;
126
138
}
127
- CanMakeProgress :: AbleToMakeProgress
128
139
}
129
140
}
141
+ None
130
142
}
131
143
132
- /// Attempts to load the data and returns if it is able to make progress.
133
- ///
134
- /// Note: F needs to return `AwaitingType<T>` and not T because it needs to
135
- /// be able to be pending if T is not ready.
144
+ #[ cfg( feature = "egui" ) ]
145
+ /// Wraps [Self::egui_poll_mut] and returns an immutable reference
136
146
#[ must_use]
137
- pub fn get < F > ( & mut self , fetch_fn : F ) -> CanMakeProgress
138
- where
139
- F : FnOnce ( ) -> Awaiting < T , E > ,
140
- {
141
- match self {
142
- DataState :: None => {
143
- let rx = fetch_fn ( ) ;
144
- * self = DataState :: AwaitingResponse ( rx) ;
145
- CanMakeProgress :: AbleToMakeProgress
146
- }
147
- DataState :: AwaitingResponse ( rx) => {
148
- if let Some ( new_state) = Self :: await_data ( rx) {
149
- * self = new_state;
150
- }
151
- CanMakeProgress :: AbleToMakeProgress
152
- }
153
- DataState :: Present ( _data) => {
154
- // Does nothing data is already present
155
- CanMakeProgress :: UnableToMakeProgress
156
- }
157
- DataState :: Failed ( _e) => {
158
- // Have no way to let the user know there is an error nothing we
159
- // can do here
160
- CanMakeProgress :: UnableToMakeProgress
161
- }
162
- }
147
+ pub fn egui_poll ( & mut self , ui : & mut egui:: Ui , error_btn_text : Option < & str > ) -> Option < & T > {
148
+ self . egui_poll_mut ( ui, error_btn_text) . map ( |x| & * x)
163
149
}
164
150
165
151
/// Checks to see if the data is ready and if it is returns a new [`Self`]
@@ -185,6 +171,31 @@ impl<T, E: ErrorBounds> DataState<T, E> {
185
171
} )
186
172
}
187
173
174
+ /// Returns a reference to the inner data if available otherwise None.
175
+ ///
176
+ /// NOTE: This function does not poll to get the data ready if the state is
177
+ /// still awaiting
178
+ pub fn present ( & self ) -> Option < & T > {
179
+ if let Self :: Present ( data) = self {
180
+ Some ( data)
181
+ } else {
182
+ None
183
+ }
184
+ }
185
+
186
+ /// Returns a mutable reference to the inner data if available otherwise
187
+ /// None
188
+ ///
189
+ /// NOTE: This function does not poll to get the data ready if the state is
190
+ /// still awaiting
191
+ pub fn present_mut ( & mut self ) -> Option < & mut T > {
192
+ if let Self :: Present ( data) = self {
193
+ Some ( data)
194
+ } else {
195
+ None
196
+ }
197
+ }
198
+
188
199
/// Returns `true` if the data state is [`Present`].
189
200
///
190
201
/// [`Present`]: DataState::Present
0 commit comments