Skip to content

Commit 99d1355

Browse files
authored
4.x: Streamable.stream() DisposableContainer -> StreamerCancellation (#8221)
* 4.x: Streamable.stream() DisposableContainer -> StreamerCancellation * remove unused never disposable container, coverage
1 parent b5ebbd9 commit 99d1355

47 files changed

Lines changed: 257 additions & 268 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/main/java/io/reactivex/rxjava4/core/Streamable.java

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
///
3434
/// The lifecycle of the sequence is as follows:
3535
///
36-
/// - consumer calls {@link #stream(DisposableContainer)}
36+
/// - consumer calls {@link #stream(StreamerCancellation)}
3737
/// - consumer calls {@link Streamer#next()} in a loop and consumer checks if what
3838
/// the {@link CompletionStage} outcome is:
3939
/// - if it succeeded with a boolean {@code true}, it is safe to call {@link Streamer#current()}.
@@ -44,7 +44,7 @@
4444
/// It is always necessary to have the consumer call {@code finish} because that is responsible for cleaning up
4545
/// resources of the upstream.
4646
///
47-
/// Downstream cancellations are signaled via the [DisposableContainer], where operators can register their own
47+
/// Downstream cancellations are signaled via the [StreamerCancellation], where operators can register their own
4848
/// [Disposable]s that get disposed. Because dispose can happen at any time and asynchronously to the consumption loop,
4949
/// the sensitive sources must complete their waiting `CompletionStage` returned by `next` exceptionally via a
5050
/// [CancellationException]. This will unblock the loops and invoke the `finish` method of the lifecycle at
@@ -72,12 +72,24 @@ public interface Streamable<@NonNull T> {
7272

7373
/**
7474
* Realizes the stream and returns an interface that lets one consume it.
75-
* @param cancellation where to register and listen for cancellation calls.
75+
* <p>
76+
* Implementations are not meant to dispose the {@code cancellation} as it is the
77+
* privilege of whatever calls the {@code stream} method. If you need to talk to other
78+
* {@code Streamable}s, use the {@link StreamerCancellation#derive()} to gain access to
79+
* a fully fledged {@link DisposableContainer} where you can dispose it without disposing
80+
* the parent {@code cancellation} instance by accident.
81+
* <p>
82+
* It is recommened you {@link StreamerCancellation#remove(Disposable)} or
83+
* {@link StreamerCancellation#delete(Disposable)} any extra resources you added
84+
* via {@link StreamerCancellation#add(Disposable)} when your operator
85+
* reaches the {@link Streamer#finish()} call.
86+
* @param cancellation where to register, check and listen for cancellation calls via
87+
* its {@link StreamerCancellation#isDisposed()}
7688
* @return the Streamer instance to consume.
7789
*/
7890
@CheckReturnValue
7991
@NonNull
80-
Streamer<T> stream(@NonNull DisposableContainer cancellation);
92+
Streamer<T> stream(@NonNull StreamerCancellation cancellation);
8193

8294
// oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
8395
// Data sources and wrappers
@@ -561,7 +573,7 @@ static Streamable<Long> timer(long delay, TimeUnit unit, ExecutorService executo
561573
* once the {@code Streamable} terminated.
562574
* @param <T> the element type of the sequence
563575
* @param <R> the resource type
564-
* @param resourceSupplier supplies a resource object per {@link #stream(DisposableContainer)} call
576+
* @param resourceSupplier supplies a resource object per {@link #stream(StreamerCancellation)} call
565577
* @param resourceMapper maps the supplied resource into a {@code Streamable} source
566578
* @param resourceCleaner cleans up the supplied resource
567579
* @return the new {@code Streamable} instance
@@ -725,7 +737,7 @@ default Streamable<T> intercept(StreamableInterceptConfig<T> config) {
725737
/**
726738
* <strong>This method requires advanced knowledge about building operators, please consider
727739
* other standard composition methods first;</strong>
728-
* Returns a {@code Streamable} instance which when its {@link #stream(DisposableContainer)} is invoked,
740+
* Returns a {@code Streamable} instance which when its {@link #stream(StreamerCancellation)} is invoked,
729741
* applies the specified operator callback to the upstream {@link Streamer} to produce
730742
* an actual {@code Streamer} instance to be handed downstream.
731743
* <p>

src/main/java/io/reactivex/rxjava4/core/StreamableOperator.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
package io.reactivex.rxjava4.core;
1515

1616
import io.reactivex.rxjava4.annotations.NonNull;
17-
import io.reactivex.rxjava4.disposables.DisposableContainer;
17+
import io.reactivex.rxjava4.disposables.StreamerCancellation;
1818

1919
/**
2020
* Interface to map/wrap an upstream {@link Streamer} to an downstream {@code Streamer}.
@@ -27,12 +27,12 @@
2727
public interface StreamableOperator<@NonNull T, @NonNull R> {
2828
/**
2929
* Applies a function to the upstream {@link Streamer} and returns a new downstream {@code Streamer}.
30-
* @param container the {@link DisposableContainer} handling the cancellation propagation for the downstream
30+
* @param container the {@link StreamerCancellation} handling the cancellation propagation for the downstream
3131
* @param streamer the upstream {@code Streamer} instance
3232
* @return the downstream {@code Streamer} instance
3333
* @throws Throwable on failure
3434
*/
3535
@NonNull
36-
Streamer<? extends R> apply(@NonNull DisposableContainer container,
36+
Streamer<? extends R> apply(@NonNull StreamerCancellation container,
3737
@NonNull Streamer<? extends T> streamer) throws Throwable;
3838
}

src/main/java/io/reactivex/rxjava4/core/config/StreamableInterceptConfig.java

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,30 +18,31 @@
1818

1919
import io.reactivex.rxjava4.annotations.NonNull;
2020
import io.reactivex.rxjava4.core.*;
21-
import io.reactivex.rxjava4.disposables.DisposableContainer;
21+
import io.reactivex.rxjava4.disposables.*;
2222
import io.reactivex.rxjava4.functions.*;
2323

2424
/**
2525
* Configuration record the intercept() operator with various lifecylce-stage transforming callbacks
2626
* @param <T> the element type of the sequence
27-
* @param onStream called when the {@link Streamable#stream(io.reactivex.rxjava4.disposables.DisposableContainer)} is invoked
27+
* @param onStream called when the {@link Streamable#stream(StreamerCancellation)} is invoked
2828
* @param onNext called when the {@link Streamer#next()} is invoked
2929
* @param onCurrent called when the {@link Streamer#current()} is invoked
3030
* @param onFinish called when the {@link Streamer#finish()} is invoked
3131
* @since 4.0.0
3232
*/
3333
public record StreamableInterceptConfig<T>(
34-
@NonNull BiFunction<? super DisposableContainer, ? super Streamer<? extends T>, ? extends Streamer<? extends T>> onStream,
35-
@NonNull BiFunction<? super DisposableContainer, ? super CompletionStage<Boolean>, ? extends CompletionStage<Boolean>> onNext,
34+
@NonNull BiFunction<? super StreamerCancellation, ? super Streamer<? extends T>, ? extends Streamer<? extends T>> onStream,
35+
@NonNull BiFunction<? super StreamerCancellation, ? super CompletionStage<Boolean>, ? extends CompletionStage<Boolean>> onNext,
3636
@NonNull Function<? super T, ? extends T> onCurrent,
37-
@NonNull BiFunction<? super DisposableContainer, ? super CompletionStage<Void>, ? extends CompletionStage<Void>> onFinish
37+
@NonNull BiFunction<? super StreamerCancellation, ? super CompletionStage<Void>, ? extends CompletionStage<Void>> onFinish
3838
) {
3939

4040
/**
4141
* Constructs a configuration with a custom {@link #onNext()} intercept and everything else is pass-through.
4242
* @param onNext the callback for intercepting the {@code next()} calls
4343
*/
44-
public StreamableInterceptConfig(@NonNull BiFunction<? super DisposableContainer, ? super CompletionStage<Boolean>, ? extends CompletionStage<Boolean>> onNext) {
44+
public StreamableInterceptConfig(
45+
@NonNull BiFunction<? super StreamerCancellation, ? super CompletionStage<Boolean>, ? extends CompletionStage<Boolean>> onNext) {
4546
this((_, v) -> v, onNext, v -> v, (_, v) -> v);
4647
}
4748

@@ -55,7 +56,7 @@ public StreamableInterceptConfig(@NonNull Function<? super T, ? extends T> onCur
5556

5657
/**
5758
* Constructs a fully configured record.
58-
* @param onStream called when the {@link Streamable#stream(io.reactivex.rxjava4.disposables.DisposableContainer)} is invoked
59+
* @param onStream called when the {@link Streamable#stream(StreamerCancellation)} is invoked
5960
* @param onNext called when the {@link Streamer#next()} is invoked
6061
* @param onCurrent called when the {@link Streamer#current()} is invoked
6162
* @param onFinish called when the {@link Streamer#finish()} is invoked

src/main/java/io/reactivex/rxjava4/disposables/CompositeDisposable.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,8 +274,21 @@ public DisposableContainer derive() {
274274
var result = new CompositeDisposable();
275275

276276
add(result);
277-
result.add(Disposable.fromRunnable(() -> delete(result)));
277+
result.add(new DerivedCleaner(this, result));
278278

279279
return result;
280280
}
281+
282+
record DerivedCleaner(DisposableContainer parent, Disposable child) implements Disposable {
283+
284+
@Override
285+
public void dispose() {
286+
parent.delete(child);
287+
}
288+
289+
@Override
290+
public boolean isDisposed() {
291+
return child.isDisposed();
292+
}
293+
}
281294
}

src/main/java/io/reactivex/rxjava4/disposables/DisposableContainer.java

Lines changed: 2 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -14,34 +14,10 @@
1414
package io.reactivex.rxjava4.disposables;
1515

1616
/**
17-
* Common interface to add and remove disposables from a container.
17+
* Common interface to add and remove {@link Disposable}s from a container.
1818
* @since 2.0
1919
*/
20-
public interface DisposableContainer extends Disposable {
21-
22-
/**
23-
* Adds a disposable to this container or disposes it if the
24-
* container has been disposed.
25-
* @param d the disposable to add, not null
26-
* @return true if successful, false if this container has been disposed
27-
*/
28-
boolean add(Disposable d);
29-
30-
/**
31-
* Removes and disposes the given disposable if it is part of this
32-
* container.
33-
* @param d the disposable to remove and dispose, not null
34-
* @return true if the operation was successful
35-
*/
36-
boolean remove(Disposable d);
37-
38-
/**
39-
* Removes but does not dispose the given disposable if it is part of this
40-
* container.
41-
* @param d the disposable to remove, not null
42-
* @return true if the operation was successful
43-
*/
44-
boolean delete(Disposable d);
20+
public interface DisposableContainer extends Disposable, StreamerCancellation {
4521

4622
/**
4723
* Removes all contained {@link Disposable}s without disposing them, making this
@@ -56,95 +32,4 @@ public interface DisposableContainer extends Disposable {
5632
*/
5733
void clear();
5834

59-
/**
60-
* Create a derived sub container that can get cancelled by this container,
61-
* but cancelling the subcontainer does not cancel this container.
62-
* @return the derived subcontainer
63-
* @since 4.0
64-
*/
65-
DisposableContainer derive();
66-
67-
/**
68-
* Registers a {@link Disposable} with this container so that it can be removed and disposed
69-
* via a simple {@link #dispose()} call to the returned Disposable.
70-
* @param d the disposable to register
71-
* @return the Disposable to trigger a {@link #remove(Disposable)}
72-
* @see #subscribe(Disposable) for non-disposing removal.
73-
* @since 4.0.0
74-
*/
75-
default Disposable register(Disposable d) {
76-
add(d);
77-
return Disposable.fromRunnable(() -> remove(d));
78-
}
79-
80-
/**
81-
* Registers a {@link Disposable} with this container so that it can be deleted, not disposed
82-
* via a simple {@link #dispose()} call to the returned Disposable.
83-
* @param d the disposable to register
84-
* @return the Disposable to trigger a {@link #remove(Disposable)}
85-
* @see #subscribe(Disposable) for non-disposing removal.
86-
* @since 4.0.0
87-
*/
88-
default Disposable subscribe(Disposable d) {
89-
add(d);
90-
return Disposable.fromRunnable(() -> delete(d));
91-
}
92-
93-
/**
94-
* The container implementation that just ignores everything, for
95-
* cases where the dispose signal has no side effects to work with.
96-
* @since 4.0.0
97-
*/
98-
DisposableContainer NEVER = new NeverDisposableContainer();
99-
100-
/**
101-
* Implementation of a never disposable container.
102-
* @since 4.0.0
103-
*/
104-
record NeverDisposableContainer() implements DisposableContainer {
105-
106-
@Override
107-
public void dispose() {
108-
// Deliberately empty
109-
}
110-
111-
@Override
112-
public boolean isDisposed() {
113-
// Who cares?
114-
return false;
115-
}
116-
117-
@Override
118-
public boolean add(Disposable d) {
119-
// Who cares?
120-
return false;
121-
}
122-
123-
@Override
124-
public boolean remove(Disposable d) {
125-
// Who cares?
126-
return false;
127-
}
128-
129-
@Override
130-
public boolean delete(Disposable d) {
131-
// Who cares?
132-
return false;
133-
}
134-
135-
@Override
136-
public void reset() {
137-
// Who cares?
138-
}
139-
140-
@Override
141-
public void clear() {
142-
// Who cares?
143-
}
144-
145-
@Override
146-
public DisposableContainer derive() {
147-
return NEVER;
148-
}
149-
}
15035
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
* Copyright (c) 2016-present, RxJava Contributors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
5+
* compliance with the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License is
10+
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
11+
* the License for the specific language governing permissions and limitations under the License.
12+
*/
13+
14+
package io.reactivex.rxjava4.disposables;
15+
16+
import io.reactivex.rxjava4.annotations.NonNull;
17+
import io.reactivex.rxjava4.core.Streamable;
18+
19+
/**
20+
* Represents non-disposable view of a {@link DisposableContainer}
21+
* that allows synchronous testing for disposed state as well as allow
22+
* adding and removing {@link Disposable} resources to be
23+
* cleaned up when the full container is disposed.
24+
* <p>
25+
* This view is provided to prevent calling {@link DisposableContainer#dispose()}
26+
* in {@link Streamable#stream(StreamerCancellation)} implementations because
27+
* disposing a stream is the privilege of the caller/downstream.
28+
* <p>
29+
* Use the {@link #derive()} to create a sub-container with full disposability access.
30+
* <p>
31+
* This interface doesn't support {@link DisposableContainer#reset()} nor
32+
* {@link DisposableContainer#clear()} because it would allow accidentally removing another
33+
* operator's added/registered {@code Disposable}s.
34+
* @since 4.0.0
35+
*/
36+
public interface StreamerCancellation {
37+
/**
38+
* Returns true if this resource has been disposed.
39+
* @return true if this resource has been disposed
40+
*/
41+
boolean isDisposed();
42+
43+
/**
44+
* Adds a disposable to this container or disposes it if the
45+
* container has been disposed.
46+
* @param d the disposable to add, not null
47+
* @return true if successful, false if this container has been disposed
48+
*/
49+
boolean add(@NonNull Disposable d);
50+
51+
/**
52+
* Removes and disposes the given disposable if it is part of this
53+
* container.
54+
* @param d the disposable to remove and dispose, not null
55+
* @return true if the operation was successful
56+
*/
57+
boolean remove(@NonNull Disposable d);
58+
59+
/**
60+
* Removes but does not dispose the given disposable if it is part of this
61+
* container.
62+
* @param d the disposable to remove, not null
63+
* @return true if the operation was successful
64+
*/
65+
boolean delete(@NonNull Disposable d);
66+
67+
/**
68+
* Create a derived sub-container that can get cancelled by this container,
69+
* but disposing the sub-container does not dispose this container.
70+
* @return the derived sub-container
71+
*/
72+
@NonNull
73+
DisposableContainer derive();
74+
75+
}

src/main/java/io/reactivex/rxjava4/internal/disposables/ListCompositeDisposable.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
/**
2323
* A disposable container that can hold onto multiple other disposables.
2424
*/
25-
public final class ListCompositeDisposable implements Disposable, DisposableContainer {
25+
public final class ListCompositeDisposable implements Disposable, DisposableContainer, StreamerCancellation {
2626

2727
List<Disposable> resources;
2828

src/main/java/io/reactivex/rxjava4/internal/operators/streamable/StreamableCollector.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121
import io.reactivex.rxjava4.annotations.NonNull;
2222
import io.reactivex.rxjava4.core.*;
23-
import io.reactivex.rxjava4.disposables.DisposableContainer;
23+
import io.reactivex.rxjava4.disposables.StreamerCancellation;
2424
import io.reactivex.rxjava4.internal.fuseable.HasUpstreamStreamableSource;
2525

2626
public record StreamableCollector<T, A, R>(
@@ -29,7 +29,7 @@ public record StreamableCollector<T, A, R>(
2929
) implements Streamable<R>, HasUpstreamStreamableSource<T> {
3030

3131
@Override
32-
public @NonNull Streamer<@NonNull R> stream(@NonNull DisposableContainer cancellation) {
32+
public @NonNull Streamer<@NonNull R> stream(@NonNull StreamerCancellation cancellation) {
3333
return new CollectorStreamable<>(
3434
source.stream(cancellation),
3535
collector.supplier().get(),

0 commit comments

Comments
 (0)