3636//! ```
3737
3838use std:: {
39- cell:: RefCell ,
4039 fmt:: Display ,
4140 future:: Future ,
4241 pin:: Pin ,
43- rc:: Rc ,
4442 task:: { Context as TaskContext , Poll , Waker } ,
4543} ;
4644
4745use crate :: {
48- context:: Context ,
46+ context:: { Context , RcDerefMut } ,
4947 observable:: { CoreObservable , Observable , ObservableType } ,
5048 observer:: Observer ,
5149} ;
@@ -103,12 +101,20 @@ pub(crate) enum State<Item, Err> {
103101}
104102
105103/// Shared state between Future and Observer
106- pub ( crate ) struct SharedState < Item , Err > {
104+ #[ doc( hidden) ]
105+ pub struct SharedState < Item , Err > {
107106 pub ( crate ) state : State < Item , Err > ,
108107 pub ( crate ) waker : Option < Waker > ,
109108 pub ( crate ) completed : bool ,
110109}
111110
111+ type IntoFutureHandle < C , Item , Err > = <C as Context >:: RcMut < SharedState < Item , Err > > ;
112+
113+ /// The concrete future returned by [`Observable::into_future()`] for a given
114+ /// observable context.
115+ pub type ObservableFutureOf < ' a , C > =
116+ ObservableFuture < IntoFutureHandle < C , <C as Observable >:: Item < ' a > , <C as Observable >:: Err > > ;
117+
112118// ============================================================================
113119// ObservableFuture
114120// ============================================================================
@@ -117,15 +123,18 @@ pub(crate) struct SharedState<Item, Err> {
117123///
118124/// This future supports both synchronous and asynchronous observables.
119125/// It uses a shared state with a waker to properly await async observables.
120- pub struct ObservableFuture < Item , Err > {
121- shared : Rc < RefCell < SharedState < Item , Err > > > ,
126+ pub struct ObservableFuture < R > {
127+ shared : R ,
122128}
123129
124- impl < Item , Err > Future for ObservableFuture < Item , Err > {
130+ impl < R , Item , Err > Future for ObservableFuture < R >
131+ where
132+ R : RcDerefMut < Target = SharedState < Item , Err > > + Clone ,
133+ {
125134 type Output = IntoFutureResult < Item , Err > ;
126135
127136 fn poll ( self : Pin < & mut Self > , cx : & mut TaskContext < ' _ > ) -> Poll < Self :: Output > {
128- let mut shared = self . shared . borrow_mut ( ) ;
137+ let mut shared = self . shared . rc_deref_mut ( ) ;
129138 if shared. completed {
130139 let result = match std:: mem:: replace ( & mut shared. state , State :: Empty ) {
131140 State :: Empty => Err ( IntoFutureError :: Empty ) ,
@@ -150,24 +159,37 @@ impl<Item, Err> Future for ObservableFuture<Item, Err> {
150159/// This observer stores the result in a shared state so it can be
151160/// retrieved after subscription completes. It supports both synchronous
152161/// and asynchronous observables by using a waker to notify the future.
153- pub struct IntoFutureObserver < Item , Err > {
154- shared : Rc < RefCell < SharedState < Item , Err > > > ,
162+ pub struct IntoFutureObserver < R > {
163+ shared : R ,
155164}
156165
157- impl < Item , Err > IntoFutureObserver < Item , Err > {
158- pub ( crate ) fn new ( shared : Rc < RefCell < SharedState < Item , Err > > > ) -> Self { Self { shared } }
166+ impl < R > Clone for IntoFutureObserver < R >
167+ where
168+ R : Clone ,
169+ {
170+ fn clone ( & self ) -> Self { Self { shared : self . shared . clone ( ) } }
171+ }
172+
173+ impl < R , Item , Err > IntoFutureObserver < R >
174+ where
175+ R : RcDerefMut < Target = SharedState < Item , Err > > + Clone ,
176+ {
177+ pub ( crate ) fn new ( shared : R ) -> Self { Self { shared } }
159178
160179 /// Wake the future if a waker is registered
161180 fn wake ( & self ) {
162- if let Some ( waker) = self . shared . borrow_mut ( ) . waker . take ( ) {
181+ if let Some ( waker) = self . shared . rc_deref_mut ( ) . waker . take ( ) {
163182 waker. wake ( ) ;
164183 }
165184 }
166185}
167186
168- impl < Item , Err > Observer < Item , Err > for IntoFutureObserver < Item , Err > {
187+ impl < R , Item , Err > Observer < Item , Err > for IntoFutureObserver < R >
188+ where
189+ R : RcDerefMut < Target = SharedState < Item , Err > > + Clone ,
190+ {
169191 fn next ( & mut self , value : Item ) {
170- let mut shared = self . shared . borrow_mut ( ) ;
192+ let mut shared = self . shared . rc_deref_mut ( ) ;
171193 match & shared. state {
172194 State :: Empty => shared. state = State :: HasValue ( value) ,
173195 State :: HasValue ( _) => {
@@ -183,46 +205,25 @@ impl<Item, Err> Observer<Item, Err> for IntoFutureObserver<Item, Err> {
183205
184206 fn error ( self , err : Err ) {
185207 {
186- let mut shared = self . shared . borrow_mut ( ) ;
208+ let mut shared = self . shared . rc_deref_mut ( ) ;
187209 shared. state = State :: Error ( err) ;
188210 shared. completed = true ;
189211 }
190212 self . wake ( ) ;
191213 }
192214
193215 fn complete ( self ) {
194- self . shared . borrow_mut ( ) . completed = true ;
216+ self . shared . rc_deref_mut ( ) . completed = true ;
195217 self . wake ( ) ;
196218 }
197219
198220 fn is_closed ( & self ) -> bool {
199221 // Stop receiving if we already have multiple values or an error
200- let shared = self . shared . borrow ( ) ;
222+ let shared = self . shared . rc_deref ( ) ;
201223 shared. completed || matches ! ( shared. state, State :: MultipleValues | State :: Error ( _) )
202224 }
203225}
204226
205- // ============================================================================
206- // Factory Function
207- // ============================================================================
208-
209- /// Creates a future from an observable.
210- ///
211- /// This function subscribes to the observable and returns a future that
212- /// resolves when the observable completes. It supports both synchronous
213- /// and asynchronous observables.
214- pub fn observable_into_future < T , E , F > ( subscribe_fn : F ) -> ObservableFuture < T , E >
215- where
216- F : FnOnce ( IntoFutureObserver < T , E > ) ,
217- {
218- let shared =
219- Rc :: new ( RefCell :: new ( SharedState { state : State :: Empty , waker : None , completed : false } ) ) ;
220- let observer = IntoFutureObserver :: new ( shared. clone ( ) ) ;
221- subscribe_fn ( observer) ;
222-
223- ObservableFuture { shared }
224- }
225-
226227// ============================================================================
227228// SupportsIntoFuture Trait (internal conversion capability)
228229// ============================================================================
@@ -239,22 +240,25 @@ where
239240 Self : ' a ,
240241{
241242 /// Convert a context-wrapped observable into an [`ObservableFuture`].
242- fn into_future ( ctx : C ) -> ObservableFuture < C :: Item < ' a > , C :: Err > ;
243+ fn into_future ( ctx : C ) -> ObservableFutureOf < ' a , C > ;
243244}
244245
245246impl < ' a , C , T > SupportsIntoFuture < ' a , C > for T
246247where
247248 C : Context < Inner = T > + Observable + ' a ,
248249 T : ObservableType + ' a ,
249250 // Use fully qualified syntax to break the cycle in trait bound computation
250- T : CoreObservable < C :: With < IntoFutureObserver < C :: Item < ' a > , C :: Err > > > ,
251+ T : CoreObservable < C :: With < IntoFutureObserver < IntoFutureHandle < C , C :: Item < ' a > , C :: Err > > > > ,
251252{
252- fn into_future ( ctx : C ) -> ObservableFuture < C :: Item < ' a > , C :: Err > {
253- observable_into_future ( |observer| {
254- let ( core, wrapped) = ctx. swap ( observer) ;
255- // NOTE: we currently drop the subscription handle, matching the old behavior.
256- core. subscribe ( wrapped) ;
257- } )
253+ fn into_future ( ctx : C ) -> ObservableFutureOf < ' a , C > {
254+ let shared: IntoFutureHandle < C , C :: Item < ' a > , C :: Err > =
255+ SharedState { state : State :: Empty , waker : None , completed : false } . into ( ) ;
256+ let observer = IntoFutureObserver :: new ( shared. clone ( ) ) ;
257+ let future = ObservableFuture { shared } ;
258+ let ( core, wrapped) = ctx. swap ( observer) ;
259+ // NOTE: we currently drop the subscription handle, matching the old behavior.
260+ core. subscribe ( wrapped) ;
261+ future
258262 }
259263}
260264
@@ -267,7 +271,10 @@ mod tests {
267271 use futures:: task:: noop_waker;
268272
269273 use super :: * ;
270- use crate :: prelude:: * ;
274+ use crate :: {
275+ prelude:: * ,
276+ rc:: { MutRc , RcDerefMut } ,
277+ } ;
271278
272279 #[ rxrust_macro:: test( local) ]
273280 async fn test_into_future_single_value ( ) {
@@ -332,11 +339,8 @@ mod tests {
332339 #[ rxrust_macro:: test]
333340 fn test_into_future_sync_observable_completes_immediately ( ) {
334341 // Synchronous observables should have completed = true after subscribe
335- let shared = Rc :: new ( RefCell :: new ( SharedState :: < i32 , ( ) > {
336- state : State :: Empty ,
337- waker : None ,
338- completed : false ,
339- } ) ) ;
342+ let shared =
343+ MutRc :: from ( SharedState :: < i32 , ( ) > { state : State :: Empty , waker : None , completed : false } ) ;
340344 let observer = IntoFutureObserver :: new ( shared. clone ( ) ) ;
341345
342346 // Simulate a sync observable
@@ -345,7 +349,7 @@ mod tests {
345349
346350 // For sync case, we need to manually complete
347351 {
348- let mut s = shared. borrow_mut ( ) ;
352+ let mut s = shared. rc_deref_mut ( ) ;
349353 s. completed = true ;
350354 }
351355
@@ -362,4 +366,30 @@ mod tests {
362366 "Synchronous observable should complete immediately"
363367 ) ;
364368 }
369+
370+ #[ cfg( not( target_arch = "wasm32" ) ) ]
371+ #[ rxrust_macro:: test]
372+ async fn test_into_future_shared_with_observe_on ( ) {
373+ let fut = Shared :: of ( 42 )
374+ . observe_on ( SharedScheduler )
375+ . into_future ( ) ;
376+
377+ assert_eq ! ( fut. await , Ok ( Ok ( 42 ) ) ) ;
378+ }
379+
380+ #[ cfg( not( target_arch = "wasm32" ) ) ]
381+ #[ rxrust_macro:: test]
382+ async fn test_into_future_shared_behavior_subject_issue_276 ( ) {
383+ let mut subject = Shared :: behavior_subject :: < bool , ( ) > ( false ) ;
384+ let fut = subject
385+ . clone ( )
386+ . observe_on ( SharedScheduler )
387+ . filter ( |v| * v)
388+ . first ( )
389+ . into_future ( ) ;
390+
391+ subject. next ( true ) ;
392+
393+ assert_eq ! ( fut. await , Ok ( Ok ( true ) ) ) ;
394+ }
365395}
0 commit comments