26
26
import rx .Observer ;
27
27
import rx .Subscription ;
28
28
import rx .util .AtomicObservableSubscription ;
29
+ import rx .util .functions .Action1 ;
29
30
import rx .util .functions .Func1 ;
30
31
import rx .util .functions .Func2 ;
31
32
@@ -43,8 +44,8 @@ public final class OperationScan {
43
44
* @return An observable sequence whose elements are the result of accumulating the output from the list of Observables.
44
45
* @see http://msdn.microsoft.com/en-us/library/hh211665(v=vs.103).aspx
45
46
*/
46
- public static <T > Func1 <Observer <T >, Subscription > scan (Observable <T > sequence , T initialValue , Func2 <T , T , T > accumulator ) {
47
- return new Accumulator <T >(sequence , initialValue , accumulator );
47
+ public static <T , R > Func1 <Observer <R >, Subscription > scan (Observable <T > sequence , R initialValue , Func2 <R , T , R > accumulator ) {
48
+ return new Accumulator <T , R >(sequence , initialValue , accumulator );
48
49
}
49
50
50
51
/**
@@ -59,26 +60,49 @@ public static <T> Func1<Observer<T>, Subscription> scan(Observable<T> sequence,
59
60
* @see http://msdn.microsoft.com/en-us/library/hh211665(v=vs.103).aspx
60
61
*/
61
62
public static <T > Func1 <Observer <T >, Subscription > scan (Observable <T > sequence , Func2 <T , T , T > accumulator ) {
62
- return new Accumulator <T >(sequence , null , accumulator );
63
+ return new AccuWithoutInitialValue <T >(sequence , accumulator );
63
64
}
64
65
65
- private static class Accumulator <T > implements Func1 <Observer <T >, Subscription > {
66
+ private static class AccuWithoutInitialValue <T > implements Func1 <Observer <T >, Subscription > {
66
67
private final Observable <T > sequence ;
67
- private final T initialValue ;
68
- private Func2 <T , T , T > accumlatorFunction ;
68
+ private final Func2 <T , T , T > accumlatorFunction ;
69
+ private T initialValue ;
70
+
71
+ private AccuWithoutInitialValue (Observable <T > sequence , Func2 <T , T , T > accumulator ) {
72
+ this .sequence = sequence ;
73
+ this .accumlatorFunction = accumulator ;
74
+ }
75
+
76
+ @ Override
77
+ public Subscription call (final Observer <T > observer ) {
78
+ sequence .take (1 ).subscribe (new Action1 <T >() {
79
+ @ Override
80
+ public void call (T value ) {
81
+ initialValue = value ;
82
+ observer .onNext (value );
83
+ }
84
+ });
85
+ Accumulator <T , T > scan = new Accumulator <T , T >(sequence /* FIXME .drop(1) */ , initialValue , accumlatorFunction );
86
+ return scan .call (observer );
87
+ }
88
+ }
89
+
90
+ private static class Accumulator <T , R > implements Func1 <Observer <R >, Subscription > {
91
+ private final Observable <T > sequence ;
92
+ private final R initialValue ;
93
+ private final Func2 <R , T , R > accumlatorFunction ;
69
94
private final AtomicObservableSubscription subscription = new AtomicObservableSubscription ();
70
95
71
- private Accumulator (Observable <T > sequence , T initialValue , Func2 <T , T , T > accumulator ) {
96
+ private Accumulator (Observable <T > sequence , R initialValue , Func2 <R , T , R > accumulator ) {
72
97
this .sequence = sequence ;
73
98
this .initialValue = initialValue ;
74
99
this .accumlatorFunction = accumulator ;
75
100
}
76
101
77
- public Subscription call ( final Observer < T > observer ) {
78
-
102
+ @ Override
103
+ public Subscription call ( final Observer < R > observer ) {
79
104
return subscription .wrap (sequence .subscribe (new Observer <T >() {
80
- private T acc = initialValue ;
81
- private boolean hasSentInitialValue = false ;
105
+ private R acc = initialValue ;
82
106
83
107
/**
84
108
* We must synchronize this because we can't allow
@@ -87,26 +111,11 @@ public Subscription call(final Observer<T> observer) {
87
111
*
88
112
* Because it's synchronized it's using non-atomic variables since everything in this method is single-threaded
89
113
*/
114
+ @ Override
90
115
public synchronized void onNext (T value ) {
91
- if (acc == null ) {
92
- // we assume that acc is not allowed to be returned from accumulatorValue
93
- // so it's okay to check null as being the state we initialize on
94
- acc = value ;
95
- // this is all we do for this first value if we didn't have an initialValue
96
- return ;
97
- }
98
- if (!hasSentInitialValue ) {
99
- hasSentInitialValue = true ;
100
- observer .onNext (acc );
101
- }
102
-
103
116
try {
104
117
105
118
acc = accumlatorFunction .call (acc , value );
106
- if (acc == null ) {
107
- onError (new IllegalArgumentException ("Null is an unsupported return value for an accumulator." ));
108
- return ;
109
- }
110
119
observer .onNext (acc );
111
120
} catch (Exception ex ) {
112
121
observer .onError (ex );
@@ -115,16 +124,13 @@ public synchronized void onNext(T value) {
115
124
}
116
125
}
117
126
127
+ @ Override
118
128
public void onError (Exception ex ) {
119
129
observer .onError (ex );
120
130
}
121
131
122
- // synchronized because we access 'hasSentInitialValue'
123
- public synchronized void onCompleted () {
124
- // if only one sequence value existed, we send it without any accumulation
125
- if (!hasSentInitialValue ) {
126
- observer .onNext (acc );
127
- }
132
+ @ Override
133
+ public void onCompleted () {
128
134
observer .onCompleted ();
129
135
}
130
136
}));
0 commit comments