Skip to content

Commit 9b7aebf

Browse files
Cleaned up subscriptions to make them idempotent when called from either side.
1 parent 4ef1a37 commit 9b7aebf

5 files changed

Lines changed: 60 additions & 49 deletions

File tree

‎language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Scheduler.scala‎

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -180,17 +180,6 @@ trait Scheduler {
180180
work{ t1.call() }
181181
}
182182
}))
183-
//action1[action0]
184-
185-
// val subscription = new rx.subscriptions.MultipleAssignmentSubscription()
186-
//
187-
// subscription.setSubscription(
188-
// this.schedule(scheduler => {
189-
// def loop(): Unit = subscription.setSubscription(scheduler.schedule{ work{ loop() }})
190-
// loop()
191-
// subscription
192-
// }))
193-
// subscription
194183
}
195184

196185
/**

‎language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/Subscription.scala‎

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -26,28 +26,24 @@ import java.util.concurrent.atomic.AtomicBoolean
2626
*/
2727
trait Subscription {
2828

29-
private [scala] val asJavaSubscription: rx.Subscription = new rx.Subscription {
30-
override def unsubscribe(){ Subscription.this.unsubscribe() }
31-
}
32-
29+
private [scala] val asJavaSubscription: rx.Subscription
30+
private [scala] val unsubscribed = new AtomicBoolean(false)
3331

3432
/**
3533
* Call this method to stop receiving notifications on the Observer that was registered when
3634
* this Subscription was received.
3735
*/
38-
def unsubscribe(): Unit = { unsubscribed.set(true) }
36+
def unsubscribe() = asJavaSubscription.unsubscribe()
3937

4038
/**
4139
* Checks if the subscription is unsubscribed.
4240
*/
43-
def isUnsubscribed: Boolean = unsubscribed.get()
44-
private [scala] val unsubscribed = new AtomicBoolean(false)
41+
def isUnsubscribed = unsubscribed.get()
4542

4643
}
4744

4845
object Subscription {
4946

50-
5147
/**
5248
* Creates an [[rx.lang.scala.Subscription]] from an [[rx.Subscription]]. ß
5349
*/
@@ -57,24 +53,22 @@ object Subscription {
5753
case x: rx.subscriptions.CompositeSubscription => new rx.lang.scala.subscriptions.CompositeSubscription(x)
5854
case x: rx.subscriptions.MultipleAssignmentSubscription => new rx.lang.scala.subscriptions.MultipleAssignmentSubscription(x)
5955
case x: rx.subscriptions.SerialSubscription => new rx.lang.scala.subscriptions.SerialSubscription(x)
60-
case x: rx.Subscription => apply { x.unsubscribe() }
56+
case x: rx.Subscription => apply{ x.unsubscribe }
6157
}
6258
}
6359

6460
/**
6561
* Creates an [[rx.lang.scala.Subscription]] that invokes the specified action when unsubscribed.
6662
*/
67-
def apply(u: => Unit): Subscription = {
68-
new Subscription() {
69-
override def unsubscribe(): Unit = {
70-
if(!super.isUnsubscribed) { u; super.unsubscribe() }
71-
}
63+
def apply(u: => Unit): Subscription = new Subscription() {
64+
val asJavaSubscription = new rx.Subscription {
65+
override def unsubscribe() { if(unsubscribed.compareAndSet(false, true)) { u } }
7266
}
7367
}
7468

7569
/**
76-
* Checks if the subscription is unsubscribed.
70+
* Creates an empty [[rx.lang.scala.Subscription]].
7771
*/
78-
def apply(): Subscription = { new Subscription {} }
72+
def apply(): Subscription = Subscription {}
7973

8074
}

‎language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/subscriptions/BooleanSubscription.scala‎

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,22 @@ package rx.lang.scala.subscriptions
1717

1818
import rx.lang.scala._
1919

20+
private [scala] object BooleanSubscription {
21+
def apply(): BooleanSubscription = new BooleanSubscription(new rx.subscriptions.BooleanSubscription())
22+
}
23+
2024
/**
2125
* Represents a [[rx.lang.scala.Subscription]] that can be checked for status.
2226
*/
23-
private [scala] class BooleanSubscription private[scala] (override val asJavaSubscription: rx.subscriptions.BooleanSubscription)
27+
private [scala] class BooleanSubscription private[scala] (boolean: rx.subscriptions.BooleanSubscription)
2428
extends Subscription {
2529

26-
//override def asJavaSubscription = subscription
27-
28-
/**
29-
* Checks whether the subscription has been unsubscribed.
30-
*/
31-
override def isUnsubscribed: Boolean = asJavaSubscription.isUnsubscribed
32-
override def unsubscribe(): Unit = asJavaSubscription.unsubscribe()
30+
val asJavaSubscription: rx.subscriptions.BooleanSubscription = new rx.subscriptions.BooleanSubscription() {
31+
override def unsubscribe(): Unit = {
32+
if(unsubscribed.compareAndSet(false, true)) {
33+
if(!boolean.isUnsubscribed) { boolean.unsubscribe() }
34+
}
35+
}
36+
override def isUnsubscribed(): Boolean = unsubscribed.get() || boolean.isUnsubscribed
37+
}
3338
}

‎language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/subscriptions/SerialSubscription.scala‎

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,38 +17,39 @@ package rx.lang.scala.subscriptions
1717

1818
import rx.lang.scala._
1919

20-
2120
object SerialSubscription {
2221

2322
/**
2423
* Creates a [[rx.lang.scala.subscriptions.SerialSubscription]].
2524
*/
26-
def apply(): SerialSubscription = {
27-
new SerialSubscription(new rx.subscriptions.SerialSubscription())
28-
}
25+
def apply(): SerialSubscription = new SerialSubscription(new rx.subscriptions.SerialSubscription())
2926

3027
/**
3128
* Creates a [[rx.lang.scala.subscriptions.SerialSubscription]] that invokes the specified action when unsubscribed.
3229
*/
3330
def apply(unsubscribe: => Unit): SerialSubscription = {
34-
val s= SerialSubscription()
35-
s.subscription = Subscription{ unsubscribe }
36-
s
31+
SerialSubscription().subscription = Subscription(unsubscribe)
3732
}
3833
}
3934

4035
/**
4136
* Represents a [[rx.lang.scala.Subscription]] that can be checked for status.
4237
*/
43-
class SerialSubscription private[scala] (override val asJavaSubscription: rx.subscriptions.SerialSubscription) extends Subscription {
38+
class SerialSubscription private[scala] (serial: rx.subscriptions.SerialSubscription) extends Subscription {
4439

45-
//override def asJavaSubscription = s
46-
/**
47-
* Unsubscribes this subscription, setting isUnsubscribed to true.
40+
/*
41+
* As long as rx.subscriptions.SerialSubscription has no isUnsubscribed,
42+
* we need to intercept and do it ourselves.
4843
*/
49-
override def unsubscribe(): Unit = { asJavaSubscription.unsubscribe(); unsubscribed.set(true) }
44+
val asJavaSubscription: rx.subscriptions.SerialSubscription = new rx.subscriptions.SerialSubscription() {
45+
override def unsubscribe(): Unit = {
46+
if(unsubscribed.compareAndSet(false, true)) { serial.unsubscribe() }
47+
}
48+
override def setSubscription(subscription: rx.Subscription): Unit = serial.setSubscription(subscription)
49+
override def getSubscription(): rx.Subscription = serial.getSubscription()
50+
}
5051

51-
def subscription_=(value: Subscription): Unit = asJavaSubscription.setSubscription(value.asJavaSubscription)
52+
def subscription_=(value: Subscription): this.type = { asJavaSubscription.setSubscription(value.asJavaSubscription); this }
5253
def subscription: Subscription = Subscription(asJavaSubscription.getSubscription)
5354

5455
}

‎language-adaptors/rxjava-scala/src/test/scala/rx/lang/scala/SubscriptionTests.scala‎

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,13 @@ class SubscriptionTests extends JUnitSuite {
2424
assertFalse(subscription.isUnsubscribed)
2525

2626
subscription.unsubscribe()
27+
2728
assertTrue(subscription.isUnsubscribed)
2829
}
2930

3031
@Test
3132
def subscriptionUnsubscribeIdempotent() {
33+
3234
var called = false
3335

3436
val subscription = Subscription{ called = !called }
@@ -37,10 +39,12 @@ class SubscriptionTests extends JUnitSuite {
3739
assertFalse(subscription.isUnsubscribed)
3840

3941
subscription.unsubscribe()
42+
4043
assertTrue(called)
4144
assertTrue(subscription.isUnsubscribed)
4245

4346
subscription.unsubscribe()
47+
4448
assertTrue(called)
4549
assertTrue(subscription.isUnsubscribed)
4650
}
@@ -62,11 +66,14 @@ class SubscriptionTests extends JUnitSuite {
6266

6367
assertTrue(composite.isUnsubscribed)
6468
assertTrue(s0.isUnsubscribed)
65-
assertTrue(s0.isUnsubscribed)
69+
assertTrue(s1.isUnsubscribed)
6670

6771
val s2 = Subscription{}
72+
6873
assertFalse(s2.isUnsubscribed)
74+
6975
composite += s2
76+
7077
assertTrue(s2.isUnsubscribed)
7178

7279
}
@@ -84,7 +91,9 @@ class SubscriptionTests extends JUnitSuite {
8491
assertTrue(s0.isUnsubscribed)
8592

8693
composite.unsubscribe()
94+
8795
assertTrue(composite.isUnsubscribed)
96+
assertTrue(s0.isUnsubscribed)
8897
}
8998

9099
@Test
@@ -99,21 +108,27 @@ class SubscriptionTests extends JUnitSuite {
99108
assertFalse(s1.isUnsubscribed)
100109

101110
multiple.subscription = s0
111+
102112
assertFalse(s0.isUnsubscribed)
103113
assertFalse(s1.isUnsubscribed)
104114

105115
multiple.subscription = s1
116+
106117
assertFalse(s0.isUnsubscribed) // difference with SerialSubscription
107118
assertFalse(s1.isUnsubscribed)
108119

109120
multiple.unsubscribe()
121+
110122
assertTrue(multiple.isUnsubscribed)
111123
assertFalse(s0.isUnsubscribed)
112124
assertTrue(s1.isUnsubscribed)
113125

114126
val s2 = Subscription()
127+
115128
assertFalse(s2.isUnsubscribed)
129+
116130
multiple.subscription = s2
131+
117132
assertTrue(s2.isUnsubscribed)
118133
assertFalse(s0.isUnsubscribed)
119134
}
@@ -130,20 +145,27 @@ class SubscriptionTests extends JUnitSuite {
130145
assertFalse(s1.isUnsubscribed)
131146

132147
serial.subscription = s0
148+
133149
assertFalse(s0.isUnsubscribed)
134150
assertFalse(s1.isUnsubscribed)
135151

136152
serial.subscription = s1
153+
137154
assertTrue(s0.isUnsubscribed) // difference with MultipleAssignmentSubscription
138155
assertFalse(s1.isUnsubscribed)
139156

140157
serial.unsubscribe()
158+
141159
assertTrue(serial.isUnsubscribed)
142160
assertTrue(s1.isUnsubscribed)
143161

144162
val s2 = Subscription()
163+
145164
assertFalse(s2.isUnsubscribed)
165+
146166
serial.subscription = s2
167+
147168
assertTrue(s2.isUnsubscribed)
148169
}
170+
149171
}

0 commit comments

Comments
 (0)