Repository navigation
Expand file tree
/
Copy pathBasicFuseableObserver.java
More file actions
226 lines (193 loc) · 6.77 KB
/
Copy pathBasicFuseableObserver.java
File metadata and controls
226 lines (193 loc) · 6.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
/**
* Copyright 2016 Netflix, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
* the License for the specific language governing permissions and limitations under the License.
*/
package io.reactivex.internal.subscribers.observable;
import io.reactivex.Observer;
import io.reactivex.disposables.Disposable;
import io.reactivex.exceptions.Exceptions;
import io.reactivex.internal.disposables.DisposableHelper;
import io.reactivex.internal.functions.ObjectHelper;
import io.reactivex.internal.fuseable.QueueDisposable;
import io.reactivex.plugins.RxJavaPlugins;
/**
* Base class for a fuseable intermediate observer.
* @param <T> the upstream value type
* @param <R> the downstream value type
*/
public abstract class BasicFuseableObserver<T, R> implements Observer<T>, QueueDisposable<R> {
/** The downstream subscriber. */
protected final Observer<? super R> actual;
/** The upstream subscription. */
protected Disposable s;
/** The upstream's QueueDisposable if not null. */
protected QueueDisposable<T> qs;
/** Flag indicating no further onXXX event should be accepted. */
protected boolean done;
/** Holds the established fusion mode of the upstream. */
protected int sourceMode;
/**
* Construct a BasicFuseableObserver by wrapping the given subscriber.
* @param actual the subscriber, not null (not verified)
*/
public BasicFuseableObserver(Observer<? super R> actual) {
this.actual = actual;
}
// final: fixed protocol steps to support fuseable and non-fuseable upstream
@SuppressWarnings("unchecked")
@Override
public final void onSubscribe(Disposable s) {
if (DisposableHelper.validate(this.s, s)) {
this.s = s;
if (s instanceof QueueDisposable) {
this.qs = (QueueDisposable<T>)s;
}
if (beforeDownstream()) {
actual.onSubscribe(this);
afterDownstream();
}
}
}
/**
* Override this to perform actions before the call {@code actual.onSubscribe(this)} happens.
* @return true if onSubscribe should continue with the call
*/
protected boolean beforeDownstream() {
return true;
}
/**
* Override this to perform actions after the call to {@code actual.onSubscribe(this)} happened.
*/
protected void afterDownstream() {
// default no-op
}
// -----------------------------------
// Convenience and state-aware methods
// -----------------------------------
/**
* Emits the value to the actual subscriber if {@link #done} is false.
* @param value the value to signal
*/
protected final void next(R value) {
if (done) {
return;
}
actual.onNext(value);
}
@Override
public void onError(Throwable t) {
if (done) {
RxJavaPlugins.onError(t);
return;
}
done = true;
actual.onError(t);
}
/**
* Rethrows the throwable if it is a fatal exception or calls {@link #onError(Throwable)}.
* @param t the throwable to rethrow or signal to the actual subscriber
*/
protected final void fail(Throwable t) {
Exceptions.throwIfFatal(t);
s.dispose();
onError(t);
}
@Override
public void onComplete() {
if (done) {
return;
}
done = true;
actual.onComplete();
}
/**
* Checks if the value is null and if so, throws a NullPointerException.
* @param value the value to check
* @param message the message to indicate the source of the value
* @return the value if not null
*/
protected final <V> V nullCheck(V value, String message) {
return ObjectHelper.requireNonNull(value, message);
}
/**
* Calls the upstream's QueueDisposable.requestFusion with the mode and
* saves the established mode in {@link #sourceMode}.
* <p>
* If the upstream doesn't support fusion ({@link #qs} is null), the method
* returns {@link QueueDisposable#NONE}.
* @param mode the fusion mode requested
* @return the established fusion mode
*/
protected final int transitiveFusion(int mode) {
QueueDisposable<T> qs = this.qs;
if (qs != null) {
int m = qs.requestFusion(mode);
if (m != NONE) {
sourceMode = m;
}
return m;
}
return NONE;
}
/**
* Calls the upstream's QueueDisposable.requestFusion with the mode and
* saves the established mode in {@link #sourceMode} if that mode doesn't
* have the {@link QueueDisposable#BOUNDARY} flag set.
* <p>
* If the upstream doesn't support fusion ({@link #qs} is null), the method
* returns {@link QueueDisposable#NONE}.
* @param mode the fusion mode requested
* @return the established fusion mode
*/
protected final int transitiveBoundaryFusion(int mode) {
QueueDisposable<T> qs = this.qs;
if (qs != null) {
if ((mode & BOUNDARY) == 0) {
int m = qs.requestFusion(mode);
if (m != NONE) {
sourceMode = m;
}
return m;
}
}
return NONE;
}
// --------------------------------------------------------------
// Default implementation of the RS and QS protocol (can be overridden)
// --------------------------------------------------------------
@Override
public void dispose() {
s.dispose();
}
@Override
public boolean isDisposed() {
return s.isDisposed();
}
@Override
public boolean isEmpty() {
return qs.isEmpty();
}
@Override
public void clear() {
qs.clear();
}
// -----------------------------------------------------------
// The rest of the Queue interface methods shouldn't be called
// -----------------------------------------------------------
@Override
public final boolean offer(R e) {
throw new UnsupportedOperationException("Should not be called!");
}
@Override
public final boolean offer(R v1, R v2) {
throw new UnsupportedOperationException("Should not be called!");
}
}