Skip to content

Commit 4b46450

Browse files
authored
Strict nullability with : Any, and made RxBoxImp a bit more efficient (#12)
2 parents 68cc247 + 9621865 commit 4b46450

File tree

13 files changed

+104
-144
lines changed

13 files changed

+104
-144
lines changed

CHANGES.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22

33
## [Unreleased]
44
### Changed
5+
- **BREAKING** Replace `RxJava Disposable` with `Kotlin Job`, and remove `rxjava` completely. ([#10](https://github.com/diffplug/durian-rx/pull/10))
6+
- Add strict nullability to RxBox and improve efficiency. ([#12](https://github.com/diffplug/durian-rx/pull/12))
57
- Bump required java from 11 to 17. ([#9](https://github.com/diffplug/durian-rx/pull/9))
6-
- Replace `RxJava Disposable` with `Kotlin Job`, and remove `rxjava` completely. ([#10](https://github.com/diffplug/durian-rx/pull/10))
78

89
## [4.0.1] - 2022-12-20
910
### Fixed

src/main/java/com/diffplug/common/rx/ForwardingBox.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import kotlinx.coroutines.flow.Flow
2727
*
2828
* Especially useful for overridding set().
2929
*/
30-
open class ForwardingBox<T, BoxType : Box<T>>
30+
open class ForwardingBox<T : Any, BoxType : Box<T>>
3131
protected constructor(protected val delegate: BoxType) : Box<T> {
3232
override fun get(): T {
3333
return delegate.get()
@@ -37,7 +37,7 @@ protected constructor(protected val delegate: BoxType) : Box<T> {
3737
delegate.set(value)
3838
}
3939

40-
class Cas<T> protected constructor(delegate: CasBox<T>) :
40+
class Cas<T : Any> protected constructor(delegate: CasBox<T>) :
4141
ForwardingBox<T, CasBox<T>>(delegate), CasBox<T> {
4242
override fun compareAndSet(expect: T, update: T): Boolean {
4343
return delegate.compareAndSet(expect, update)
@@ -48,21 +48,21 @@ protected constructor(protected val delegate: BoxType) : Box<T> {
4848
}
4949
}
5050

51-
class Lock<T> protected constructor(delegate: LockBox<T>) :
51+
class Lock<T : Any> protected constructor(delegate: LockBox<T>) :
5252
ForwardingBox<T, LockBox<T>>(delegate), LockBox<T> {
5353
override fun lock(): Any {
5454
return delegate.lock()
5555
}
5656
}
5757

58-
open class Rx<T> protected constructor(delegate: RxBox<T>) :
58+
open class Rx<T : Any> protected constructor(delegate: RxBox<T>) :
5959
ForwardingBox<T, RxBox<T>>(delegate), RxBox<T> {
6060
override fun asFlow(): Flow<T> {
6161
return delegate.asFlow()
6262
}
6363
}
6464

65-
class RxLock<T> protected constructor(delegate: RxLockBox<T>) :
65+
class RxLock<T : Any> protected constructor(delegate: RxLockBox<T>) :
6666
ForwardingBox<T, RxLockBox<T>>(delegate), RxLockBox<T> {
6767
override fun lock(): Any {
6868
return delegate.lock()

src/main/java/com/diffplug/common/rx/GuardedExecutor.kt

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import java.util.concurrent.Executor
2222
import java.util.function.Supplier
2323
import kotlinx.coroutines.Deferred
2424
import kotlinx.coroutines.Job
25-
import kotlinx.coroutines.SupervisorJob
2625
import kotlinx.coroutines.flow.Flow
2726

2827
/**
@@ -33,12 +32,11 @@ import kotlinx.coroutines.flow.Flow
3332
*/
3433
open class GuardedExecutor(val delegate: RxExecutor, val guard: Chit) : Executor, RxSubscriber {
3534
override fun execute(command: Runnable) {
36-
delegate.executor().execute(guard.guard(command))
35+
delegate.executor.execute(guard.guard(command))
3736
}
3837

3938
/** Creates a runnable which runs on this Executor iff the guard widget is not disposed. */
4039
fun wrap(delegate: Runnable): Runnable {
41-
Objects.requireNonNull(delegate)
4240
return Runnable { execute(guard.guard(delegate)) }
4341
}
4442

@@ -48,7 +46,7 @@ open class GuardedExecutor(val delegate: RxExecutor, val guard: Chit) : Executor
4846
guard.runWhenDisposed { job.cancel() }
4947
job
5048
} else {
51-
SupervisorJob().apply { cancel() }
49+
Rx.sentinelJob
5250
}
5351
}
5452

src/main/java/com/diffplug/common/rx/MappedImp.java

Lines changed: 0 additions & 58 deletions
This file was deleted.
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright 2020 DiffPlug
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.diffplug.common.rx
17+
18+
import com.diffplug.common.base.Box
19+
import com.diffplug.common.base.Converter
20+
import java.util.function.Function
21+
22+
internal open class MappedImp<T : Any, R : Any, BoxType : Box<T>>(
23+
@JvmField protected val delegate: BoxType,
24+
@JvmField protected val converter: Converter<T, R>
25+
) : Box<R> {
26+
override fun get(): R = converter.convertNonNull(delegate.get())
27+
28+
override fun set(value: R) = delegate.set(converter.revertNonNull(value))
29+
30+
/** Shortcut for doing a set() on the result of a get(). */
31+
override fun modify(mutator: Function<in R, out R>): R {
32+
val result = Box.Nullable.ofNull<R>()
33+
delegate.modify { input: T ->
34+
val unmappedResult = mutator.apply(converter.convertNonNull(input))
35+
result.set(unmappedResult)
36+
converter.revertNonNull(unmappedResult)
37+
}
38+
return result.get()
39+
}
40+
41+
override fun toString(): String =
42+
"[" + delegate + " mapped to " + get() + " by " + converter + "]"
43+
}

src/main/java/com/diffplug/common/rx/MultiSelectModel.kt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,10 +171,14 @@ class MultiSelectModel<T : Any>(
171171

172172
companion object {
173173
/** Creates an Optional<Either> from an Either<Optional>. </Optional></Either> */
174-
fun <T, U> optEitherFrom(either: Either<Optional<T>, Optional<U>>): Optional<Either<T, U>> {
174+
fun <T : Any, U : Any> optEitherFrom(
175+
either: Either<Optional<T>, Optional<U>>
176+
): Optional<Either<T, U>> {
175177
return either.fold({ leftOpt: Optional<T> ->
176178
leftOpt.map { l: T -> Either.createLeft(l) }
177-
}) { rightOpt: Optional<U> -> rightOpt.map { r: U -> Either.createRight(r) } }
179+
}) { rightOpt: Optional<U> ->
180+
rightOpt.map { r: U -> Either.createRight(r) }
181+
}
178182
}
179183
}
180184
}

src/main/java/com/diffplug/common/rx/Rx.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ import kotlinx.coroutines.flow.merge
100100
* (https://diffplug.github.io/durian-swt/javadoc/snapshot/com/diffplug/common/swt/SwtExec.html)
101101
*/
102102
object Rx {
103+
@JvmStatic
103104
fun <T> createEmitFlow() =
104105
MutableSharedFlow<T>(replay = 0, extraBufferCapacity = 1, BufferOverflow.SUSPEND)
105106

@@ -132,6 +133,7 @@ object Rx {
132133
* Creates an Rx instance which will call the given consumer whenever the followed stream or
133134
* future completes, whether with an error or not, and the error (if present) will be logged.
134135
*/
136+
@JvmStatic
135137
fun <T> onTerminateLogError(onTerminate: Consumer<Optional<Throwable>>): RxListener<T> {
136138
return RxListener(Consumers.doNothing(), DefaultTerminate(onTerminate))
137139
}
@@ -371,7 +373,7 @@ object Rx {
371373

372374
/** Reliable way to sync two RxBox to each other. */
373375
@JvmStatic
374-
fun <T> sync(left: RxBox<T>, right: RxBox<T>) {
376+
fun <T : Any> sync(left: RxBox<T>, right: RxBox<T>) {
375377
sync(sameThreadExecutor(), left, right)
376378
}
377379

@@ -380,7 +382,7 @@ object Rx {
380382
* changes
381383
*/
382384
@JvmStatic
383-
fun <T> sync(subscriber: RxSubscriber, left: RxBox<T>, right: RxBox<T>) {
385+
fun <T : Any> sync(subscriber: RxSubscriber, left: RxBox<T>, right: RxBox<T>) {
384386
val firstChange = Box.Nullable.ofNull<Either<T, T>?>()
385387
subscriber.subscribe(left) { leftVal: T ->
386388
// the left changed before we could acknowledge it
@@ -449,5 +451,5 @@ object Rx {
449451
}
450452
}
451453

452-
val sentinelJob: Job = Job().apply { cancel() }
454+
@JvmStatic val sentinelJob: Job = Job().apply { cancel() }
453455
}

src/main/java/com/diffplug/common/rx/RxBox.kt

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,12 @@ import kotlinx.coroutines.flow.Flow
2424
import kotlinx.coroutines.flow.map
2525

2626
/** [RxGetter] and [Box] combined in one: a value you can set, get, and subscribe to. */
27-
interface RxBox<T> : RxGetter<T>, Box<T> {
27+
interface RxBox<T : Any> : RxGetter<T>, Box<T> {
2828
/** Returns a read-only version of this `RxBox`. */
29-
fun readOnly(): RxGetter<T> {
30-
return this
31-
}
29+
fun readOnly(): RxGetter<T> = this
3230

3331
/** Maps one `RxBox` to another `RxBox`. */
34-
override fun <R> map(converter: Converter<T, R>): RxBox<R> {
32+
override fun <R : Any> map(converter: Converter<T, R>): RxBox<R> {
3533
return RxBoxImp.Mapped(this, converter)
3634
}
3735

@@ -70,30 +68,26 @@ interface RxBox<T> : RxGetter<T>, Box<T> {
7068

7169
companion object {
7270
/** Creates an `RxBox` with the given initial value. */
73-
@JvmStatic
74-
fun <T> of(initial: T): RxBox<T> {
75-
return RxBoxImp(initial)
76-
}
71+
@JvmStatic fun <T : Any> of(initial: T): RxBox<T> = RxBoxImp(initial)
7772

7873
/**
7974
* Creates an `RxBox` which implements the "getter" part with `RxGetter`, and the setter part
8075
* with `Consumer`.
8176
*/
8277
@JvmStatic
83-
fun <T> from(getter: RxGetter<T>, setter: Consumer<T>): RxBox<T> {
84-
return object : RxBox<T> {
85-
override fun asFlow(): Flow<T> {
86-
return getter.asFlow()
87-
}
78+
fun <T : Any> from(getter: RxGetter<T>, setter: Consumer<T>): RxBox<T> =
79+
object : RxBox<T> {
80+
override fun asFlow(): Flow<T> {
81+
return getter.asFlow()
82+
}
8883

89-
override fun get(): T {
90-
return getter.get()
91-
}
84+
override fun get(): T {
85+
return getter.get()
86+
}
9287

93-
override fun set(value: T) {
94-
setter.accept(value)
88+
override fun set(value: T) {
89+
setter.accept(value)
90+
}
9591
}
96-
}
97-
}
9892
}
9993
}

src/main/java/com/diffplug/common/rx/RxBoxImp.kt

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,28 +21,22 @@ import kotlinx.coroutines.flow.MutableStateFlow
2121
import kotlinx.coroutines.flow.distinctUntilChanged
2222
import kotlinx.coroutines.flow.map
2323

24-
internal open class RxBoxImp<T> private constructor(initial: T, subject: MutableStateFlow<T>) :
25-
RxBox<T> {
26-
private var value: T = initial
27-
private val subject: MutableStateFlow<T> = subject
28-
29-
constructor(initial: T) : this(initial, MutableStateFlow(initial)) {}
24+
internal open class RxBoxImp<T : Any>(initial: T) : RxBox<T> {
25+
private val subject = MutableStateFlow(initial)
3026

3127
override fun set(newValue: T) {
32-
if (newValue != value) {
33-
value = newValue
28+
if (subject.value != newValue) {
3429
subject.value = newValue
3530
}
3631
}
3732

38-
override fun get(): T = value
33+
override fun get(): T = subject.value
3934

4035
override fun asFlow(): Flow<T> = subject
4136

42-
internal class Mapped<T, R>(delegate: RxBox<T>, converter: Converter<T, R>) :
37+
internal class Mapped<T : Any, R : Any>(delegate: RxBox<T>, converter: Converter<T, R>) :
4338
MappedImp<T, R, RxBox<T>>(delegate, converter), RxBox<R> {
44-
val flow: Flow<R> =
45-
delegate.asFlow().map { a: T -> converter.convertNonNull(a) }.distinctUntilChanged()
39+
val flow: Flow<R> = delegate.asFlow().map(converter::convertNonNull).distinctUntilChanged()
4640

4741
override fun asFlow(): Flow<R> = flow
4842
}

src/main/java/com/diffplug/common/rx/RxExecutor.kt

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,13 @@ import kotlinx.coroutines.flow.onCompletion
3333
import kotlinx.coroutines.flow.onEach
3434
import kotlinx.coroutines.launch
3535

36-
class RxExecutor
37-
internal constructor(private val executor: Executor, val dispatcher: CoroutineDispatcher) :
36+
class RxExecutor internal constructor(val executor: Executor, val dispatcher: CoroutineDispatcher) :
3837
RxSubscriber {
3938

4039
interface Has : Executor {
4140
val rxExecutor: RxExecutor
4241
}
4342

44-
fun executor() = executor
45-
4643
override fun <T> subscribe(flow: Flow<T>, listener: RxListener<T>) {
4744
subscribeDisposable(flow, listener)
4845
}

0 commit comments

Comments
 (0)