@@ -49,6 +49,7 @@ public final class UnicastSubject<T> extends Subject<T, T> {
49
49
public static <T > UnicastSubject <T > create () {
50
50
return create (16 );
51
51
}
52
+
52
53
/**
53
54
* Constructs an empty UnicastSubject instance with a capacity hint.
54
55
* <p>The capacity hint determines the internal queue's island size: the larger
@@ -59,7 +60,18 @@ public static <T> UnicastSubject<T> create() {
59
60
* @return the created BufferUntilSubscriber instance
60
61
*/
61
62
public static <T > UnicastSubject <T > create (int capacityHint ) {
62
- State <T > state = new State <T >(capacityHint , null );
63
+ State <T > state = new State <T >(capacityHint , false , null );
64
+ return new UnicastSubject <T >(state );
65
+ }
66
+
67
+ /**
68
+ * Constructs an empty UnicastSubject instance with the default capacity hint of 16 elements.
69
+ *
70
+ * @param delayError deliver pending next events before error.
71
+ * @return the created UnicastSubject instance
72
+ */
73
+ public static <T > UnicastSubject <T > create (boolean delayError ) {
74
+ State <T > state = new State <T >(16 , delayError , null );
63
75
return new UnicastSubject <T >(state );
64
76
}
65
77
@@ -78,7 +90,28 @@ public static <T> UnicastSubject<T> create(int capacityHint) {
78
90
* @return the created BufferUntilSubscriber instance
79
91
*/
80
92
public static <T > UnicastSubject <T > create (int capacityHint , Action0 onTerminated ) {
81
- State <T > state = new State <T >(capacityHint , onTerminated );
93
+ State <T > state = new State <T >(capacityHint , false , onTerminated );
94
+ return new UnicastSubject <T >(state );
95
+ }
96
+
97
+ /**
98
+ * Constructs an empty UnicastSubject instance with a capacity hint, delay error
99
+ * flag and Action0 instance to call if the subject reaches its terminal state
100
+ * or the single Subscriber unsubscribes mid-sequence.
101
+ * <p>The capacity hint determines the internal queue's island size: the larger
102
+ * it is the less frequent allocation will happen if there is no subscriber
103
+ * or the subscriber hasn't caught up.
104
+ * @param <T> the input and output value type
105
+ * @param capacityHint the capacity hint for the internal queue
106
+ * @param onTerminated the optional callback to call when subject reaches its terminal state
107
+ * or the single Subscriber unsubscribes mid-sequence. It will be called
108
+ * at most once.
109
+ * @param delayError flag indicating whether to deliver pending next events before error.
110
+ * @return the created BufferUntilSubscriber instance
111
+ */
112
+ public static <T > UnicastSubject <T > create (int capacityHint ,
113
+ Action0 onTerminated , boolean delayError ) {
114
+ State <T > state = new State <T >(capacityHint , delayError , onTerminated );
82
115
return new UnicastSubject <T >(state );
83
116
}
84
117
@@ -119,6 +152,8 @@ static final class State<T> extends AtomicLong implements Producer, Observer<T>,
119
152
final AtomicReference <Subscriber <? super T >> subscriber ;
120
153
/** The queue holding values until the subscriber arrives and catches up. */
121
154
final Queue <Object > queue ;
155
+ /** Deliver pending next events before error. */
156
+ final boolean delayError ;
122
157
/** Atomically set to true on terminal condition. */
123
158
final AtomicReference <Action0 > terminateOnce ;
124
159
/** In case the source emitted an error. */
@@ -137,10 +172,12 @@ static final class State<T> extends AtomicLong implements Producer, Observer<T>,
137
172
* reduce allocation frequency
138
173
* @param onTerminated the action to call when the subject reaches its terminal state or
139
174
* the single subscriber unsubscribes.
175
+ * @param delayError deliver pending next events before error.
140
176
*/
141
- public State (int capacityHint , Action0 onTerminated ) {
177
+ public State (int capacityHint , boolean delayError , Action0 onTerminated ) {
142
178
this .subscriber = new AtomicReference <Subscriber <? super T >>();
143
179
this .terminateOnce = onTerminated != null ? new AtomicReference <Action0 >(onTerminated ) : null ;
180
+ this .delayError = delayError ;
144
181
145
182
Queue <Object > q ;
146
183
if (capacityHint > 1 ) {
@@ -266,14 +303,14 @@ void replay() {
266
303
emitting = true ;
267
304
}
268
305
Queue <Object > q = queue ;
306
+ boolean delayError = this .delayError ;
269
307
for (;;) {
270
308
Subscriber <? super T > s = subscriber .get ();
271
309
boolean unlimited = false ;
272
310
if (s != null ) {
273
311
boolean d = done ;
274
312
boolean empty = q .isEmpty ();
275
-
276
- if (checkTerminated (d , empty , s )) {
313
+ if (checkTerminated (d , empty , delayError , s )) {
277
314
return ;
278
315
}
279
316
long r = get ();
@@ -284,7 +321,7 @@ void replay() {
284
321
d = done ;
285
322
Object v = q .poll ();
286
323
empty = v == null ;
287
- if (checkTerminated (d , empty , s )) {
324
+ if (checkTerminated (d , empty , delayError , s )) {
288
325
return ;
289
326
}
290
327
if (empty ) {
@@ -348,23 +385,28 @@ public boolean isUnsubscribed() {
348
385
* an error happened or the source terminated and the queue is empty
349
386
* @param done indicates the source has called onCompleted
350
387
* @param empty indicates if there are no more source values in the queue
388
+ * @param delayError indicates whether to deliver pending next events before error
351
389
* @param s the target Subscriber to emit events to
352
390
* @return true if this Subject reached a terminal state and the drain loop should quit
353
391
*/
354
- boolean checkTerminated (boolean done , boolean empty , Subscriber <? super T > s ) {
392
+ boolean checkTerminated (boolean done , boolean empty , boolean delayError , Subscriber <? super T > s ) {
355
393
if (s .isUnsubscribed ()) {
356
394
queue .clear ();
357
395
return true ;
358
396
}
359
397
if (done ) {
360
398
Throwable e = error ;
361
- if (e != null ) {
399
+ if (e != null && ! delayError ) {
362
400
queue .clear ();
363
401
s .onError (e );
364
402
return true ;
365
- } else
403
+ }
366
404
if (empty ) {
367
- s .onCompleted ();
405
+ if (e != null ) {
406
+ s .onError (e );
407
+ } else {
408
+ s .onCompleted ();
409
+ }
368
410
return true ;
369
411
}
370
412
}
0 commit comments