rx_ruby 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitattributes +22 -0
- data/.gitignore +173 -0
- data/.travis.yml +10 -0
- data/Gemfile +4 -0
- data/Rakefile +11 -0
- data/examples/aggregate.rb +39 -0
- data/examples/amb.rb +25 -0
- data/examples/ambproto.rb +24 -0
- data/examples/and.rb +26 -0
- data/examples/as_observable.rb +25 -0
- data/examples/average.rb +43 -0
- data/examples/buffer_with_count.rb +44 -0
- data/examples/buffer_with_time.rb +51 -0
- data/examples/case.rb +29 -0
- data/examples/catch.rb +20 -0
- data/examples/catchproto.rb +39 -0
- data/examples/combine_latest.rb +35 -0
- data/examples/combine_latestproto.rb +33 -0
- data/examples/concat.rb +22 -0
- data/examples/concat_all.rb +27 -0
- data/examples/concat_map.rb +61 -0
- data/examples/concat_map_observer.rb +29 -0
- data/examples/concatproto.rb +25 -0
- data/examples/connect.rb +41 -0
- data/examples/contains.rb +37 -0
- data/examples/count.rb +36 -0
- data/examples/create.rb +55 -0
- data/examples/debounce.rb +35 -0
- data/examples/default_if_empty.rb +35 -0
- data/examples/defer.rb +20 -0
- data/examples/delay.rb +49 -0
- data/examples/delay_with_selector.rb +63 -0
- data/examples/dematerialize.rb +22 -0
- data/examples/disposable.rb +12 -0
- data/examples/distinct.rb +43 -0
- data/examples/distinct_until_changed.rb +43 -0
- data/examples/do.rb +59 -0
- data/examples/empty.rb +16 -0
- data/examples/for.rb +26 -0
- data/examples/fork_join.rb +23 -0
- data/examples/from.rb +106 -0
- data/examples/from_array.rb +21 -0
- data/examples/from_callback.rb +21 -0
- data/examples/generate.rb +24 -0
- data/examples/group_join.rb +39 -0
- data/examples/if.rb +46 -0
- data/examples/intervals.rb +26 -0
- data/examples/merge.rb +36 -0
- data/examples/merge_all.rb +27 -0
- data/examples/multicast.rb +32 -0
- data/examples/never.rb +15 -0
- data/examples/of.rb +19 -0
- data/examples/on_error_resume_next.rb +21 -0
- data/examples/pairs.rb +26 -0
- data/examples/publish.rb +79 -0
- data/examples/range.rb +19 -0
- data/examples/reduce.rb +18 -0
- data/examples/repeat.rb +19 -0
- data/examples/return.rb +17 -0
- data/examples/scan.rb +41 -0
- data/examples/start.rb +29 -0
- data/examples/throw.rb +17 -0
- data/examples/time_intervals.rb +28 -0
- data/examples/timer.rb +26 -0
- data/examples/timestamp.rb +28 -0
- data/examples/to_a.rb +23 -0
- data/examples/to_async.rb +26 -0
- data/examples/using.rb +52 -0
- data/examples/when.rb +26 -0
- data/examples/while.rb +25 -0
- data/examples/window_with_time.rb +78 -0
- data/examples/zip.rb +27 -0
- data/examples/zip_array.rb +25 -0
- data/lib/core_ext/enumerable.rb +22 -0
- data/lib/rx_ruby.rb +27 -0
- data/lib/rx_ruby/concurrency/async_lock.rb +57 -0
- data/lib/rx_ruby/concurrency/current_thread_scheduler.rb +75 -0
- data/lib/rx_ruby/concurrency/default_scheduler.rb +51 -0
- data/lib/rx_ruby/concurrency/historical_scheduler.rb +16 -0
- data/lib/rx_ruby/concurrency/immediate_scheduler.rb +68 -0
- data/lib/rx_ruby/concurrency/local_scheduler.rb +39 -0
- data/lib/rx_ruby/concurrency/periodic_scheduler.rb +74 -0
- data/lib/rx_ruby/concurrency/scheduled_item.rb +42 -0
- data/lib/rx_ruby/concurrency/scheduler.rb +150 -0
- data/lib/rx_ruby/concurrency/virtual_time_scheduler.rb +170 -0
- data/lib/rx_ruby/core/async_lock_observer.rb +46 -0
- data/lib/rx_ruby/core/auto_detach_observer.rb +59 -0
- data/lib/rx_ruby/core/checked_observer.rb +66 -0
- data/lib/rx_ruby/core/notification.rb +161 -0
- data/lib/rx_ruby/core/observable.rb +104 -0
- data/lib/rx_ruby/core/observe_on_observer.rb +50 -0
- data/lib/rx_ruby/core/observer.rb +119 -0
- data/lib/rx_ruby/core/scheduled_observer.rb +83 -0
- data/lib/rx_ruby/core/synchronized_observer.rb +47 -0
- data/lib/rx_ruby/core/time_interval.rb +17 -0
- data/lib/rx_ruby/internal/priority_queue.rb +122 -0
- data/lib/rx_ruby/internal/util.rb +9 -0
- data/lib/rx_ruby/joins/active_plan.rb +45 -0
- data/lib/rx_ruby/joins/join_observer.rb +51 -0
- data/lib/rx_ruby/joins/pattern.rb +14 -0
- data/lib/rx_ruby/joins/plan.rb +44 -0
- data/lib/rx_ruby/linq/connectable_observable.rb +34 -0
- data/lib/rx_ruby/linq/observable/_observable_timer_date_and_period.rb +22 -0
- data/lib/rx_ruby/linq/observable/_observable_timer_time_span.rb +14 -0
- data/lib/rx_ruby/linq/observable/_observable_timer_time_span_and_period.rb +20 -0
- data/lib/rx_ruby/linq/observable/aggregate.rb +7 -0
- data/lib/rx_ruby/linq/observable/and.rb +7 -0
- data/lib/rx_ruby/linq/observable/case.rb +15 -0
- data/lib/rx_ruby/linq/observable/concat_all.rb +7 -0
- data/lib/rx_ruby/linq/observable/concat_map.rb +35 -0
- data/lib/rx_ruby/linq/observable/concat_map_observer.rb +43 -0
- data/lib/rx_ruby/linq/observable/contains.rb +28 -0
- data/lib/rx_ruby/linq/observable/debounce.rb +41 -0
- data/lib/rx_ruby/linq/observable/delay.rb +81 -0
- data/lib/rx_ruby/linq/observable/delay_with_selector.rb +64 -0
- data/lib/rx_ruby/linq/observable/do.rb +42 -0
- data/lib/rx_ruby/linq/observable/for.rb +13 -0
- data/lib/rx_ruby/linq/observable/fork_join.rb +55 -0
- data/lib/rx_ruby/linq/observable/from.rb +34 -0
- data/lib/rx_ruby/linq/observable/group_join.rb +108 -0
- data/lib/rx_ruby/linq/observable/if.rb +17 -0
- data/lib/rx_ruby/linq/observable/interval.rb +5 -0
- data/lib/rx_ruby/linq/observable/multicast.rb +14 -0
- data/lib/rx_ruby/linq/observable/of.rb +11 -0
- data/lib/rx_ruby/linq/observable/pairs.rb +7 -0
- data/lib/rx_ruby/linq/observable/pluck.rb +7 -0
- data/lib/rx_ruby/linq/observable/publish.rb +11 -0
- data/lib/rx_ruby/linq/observable/start.rb +7 -0
- data/lib/rx_ruby/linq/observable/time_interval.rb +15 -0
- data/lib/rx_ruby/linq/observable/timer.rb +26 -0
- data/lib/rx_ruby/linq/observable/timestamp.rb +9 -0
- data/lib/rx_ruby/linq/observable/to_async.rb +40 -0
- data/lib/rx_ruby/linq/observable/when.rb +36 -0
- data/lib/rx_ruby/linq/observable/while.rb +41 -0
- data/lib/rx_ruby/operators/aggregates.rb +611 -0
- data/lib/rx_ruby/operators/creation.rb +220 -0
- data/lib/rx_ruby/operators/multiple.rb +735 -0
- data/lib/rx_ruby/operators/single.rb +399 -0
- data/lib/rx_ruby/operators/standard_query_operators.rb +279 -0
- data/lib/rx_ruby/operators/synchronization.rb +47 -0
- data/lib/rx_ruby/operators/time.rb +120 -0
- data/lib/rx_ruby/subjects/async_subject.rb +161 -0
- data/lib/rx_ruby/subjects/behavior_subject.rb +149 -0
- data/lib/rx_ruby/subjects/replay_subject.rb +39 -0
- data/lib/rx_ruby/subjects/subject.rb +131 -0
- data/lib/rx_ruby/subjects/subject_extensions.rb +45 -0
- data/lib/rx_ruby/subscriptions/composite_subscription.rb +91 -0
- data/lib/rx_ruby/subscriptions/ref_count_subscription.rb +88 -0
- data/lib/rx_ruby/subscriptions/scheduled_subscription.rb +32 -0
- data/lib/rx_ruby/subscriptions/serial_subscription.rb +60 -0
- data/lib/rx_ruby/subscriptions/single_assignment_subscription.rb +64 -0
- data/lib/rx_ruby/subscriptions/subscription.rb +56 -0
- data/lib/rx_ruby/testing/cold_observable.rb +45 -0
- data/lib/rx_ruby/testing/hot_observable.rb +47 -0
- data/lib/rx_ruby/testing/mock_observer.rb +33 -0
- data/lib/rx_ruby/testing/reactive_test.rb +94 -0
- data/lib/rx_ruby/testing/recorded.rb +17 -0
- data/lib/rx_ruby/testing/test_scheduler.rb +96 -0
- data/lib/rx_ruby/testing/test_subscription.rb +22 -0
- data/lib/rx_ruby/version.rb +3 -0
- data/license.txt +13 -0
- data/readme.md +152 -0
- data/rx_ruby.gemspec +22 -0
- data/test/rx_ruby/concurrency/helpers/historical_virtual_scheduler_helper.rb +135 -0
- data/test/rx_ruby/concurrency/helpers/immediate_local_scheduler_helper.rb +51 -0
- data/test/rx_ruby/concurrency/test_async_lock.rb +56 -0
- data/test/rx_ruby/concurrency/test_current_thread_scheduler.rb +44 -0
- data/test/rx_ruby/concurrency/test_default_scheduler.rb +44 -0
- data/test/rx_ruby/concurrency/test_historical_scheduler.rb +18 -0
- data/test/rx_ruby/concurrency/test_immediate_scheduler.rb +53 -0
- data/test/rx_ruby/concurrency/test_local_scheduler.rb +12 -0
- data/test/rx_ruby/concurrency/test_periodic_scheduler.rb +53 -0
- data/test/rx_ruby/concurrency/test_scheduled_item.rb +50 -0
- data/test/rx_ruby/concurrency/test_scheduler.rb +128 -0
- data/test/rx_ruby/concurrency/test_virtual_time_scheduler.rb +14 -0
- data/test/rx_ruby/core/test_notification.rb +129 -0
- data/test/rx_ruby/core/test_observable_creation.rb +483 -0
- data/test/rx_ruby/core/test_observer.rb +634 -0
- data/test/rx_ruby/internal/test_priority_queue.rb +71 -0
- data/test/rx_ruby/subscriptions/test_composite_subscription.rb +116 -0
- data/test/rx_ruby/subscriptions/test_serial_subscription.rb +62 -0
- data/test/rx_ruby/subscriptions/test_singleassignment_subscription.rb +61 -0
- data/test/rx_ruby/subscriptions/test_subscription.rb +27 -0
- data/test/test_helper.rb +11 -0
- metadata +291 -0
@@ -0,0 +1,39 @@
|
|
1
|
+
# Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
2
|
+
|
3
|
+
require 'thread'
|
4
|
+
require 'rx_ruby/concurrency/current_thread_scheduler'
|
5
|
+
require 'rx_ruby/core/observer'
|
6
|
+
require 'rx_ruby/core/observable'
|
7
|
+
require 'rx_ruby/core/time_interval'
|
8
|
+
|
9
|
+
module RxRuby
|
10
|
+
|
11
|
+
# Represents an object that is both an observable sequence as well as an observer.
|
12
|
+
# Each notification is broadcasted to all subscribed and future observers, subject to buffer trimming policies.
|
13
|
+
class ReplaySubject
|
14
|
+
|
15
|
+
include Observer
|
16
|
+
include Observable
|
17
|
+
|
18
|
+
INFINITE_BUFFER_SIZE = Float::MAX.to_i
|
19
|
+
|
20
|
+
def initialize(buffer_size = INFINITE_BUFFER_SIZE, window_size = INFINITE_BUFFER_SIZE, scheduler = CurrentThreadScheduler.instance)
|
21
|
+
@buffer_size = buffer_size
|
22
|
+
@window_size = window_size
|
23
|
+
@scheduler = scheduler
|
24
|
+
@queue = []
|
25
|
+
@observers = []
|
26
|
+
@stopped = false
|
27
|
+
@error = nil
|
28
|
+
end
|
29
|
+
|
30
|
+
# Indicates whether the subject has observers subscribed to it.
|
31
|
+
# @return [B]
|
32
|
+
def has_observers?
|
33
|
+
observers = @observers
|
34
|
+
observers && observers.length > 0
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
# Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
2
|
+
|
3
|
+
require 'thread'
|
4
|
+
require 'rx_ruby/core/observer'
|
5
|
+
require 'rx_ruby/core/observable'
|
6
|
+
require 'rx_ruby/subscriptions/subscription'
|
7
|
+
|
8
|
+
module RxRuby
|
9
|
+
|
10
|
+
# Represents an object that is both an observable sequence as well as an observer.
|
11
|
+
# Each notification is broadcasted to all subscribed observers.
|
12
|
+
class Subject
|
13
|
+
|
14
|
+
include Observable
|
15
|
+
include Observer
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
@observers = []
|
19
|
+
@gate = Mutex.new
|
20
|
+
@disposed = false
|
21
|
+
@stopped = false
|
22
|
+
@error = nil
|
23
|
+
end
|
24
|
+
|
25
|
+
# Indicates whether the subject has observers subscribed to it.
|
26
|
+
def has_observers?
|
27
|
+
@observers && @observers.length > 0
|
28
|
+
end
|
29
|
+
|
30
|
+
# Notifies all subscribed observers about the end of the sequence.
|
31
|
+
def on_completed
|
32
|
+
os = nil
|
33
|
+
@gate.synchronize do
|
34
|
+
check_disposed
|
35
|
+
|
36
|
+
unless @stopped
|
37
|
+
os = @observers.clone
|
38
|
+
@observers = []
|
39
|
+
@stopped = true
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
os.each {|o| o.on_completed } if os
|
44
|
+
end
|
45
|
+
|
46
|
+
# Notifies all subscribed observers with the error.
|
47
|
+
def on_error(error)
|
48
|
+
raise 'error cannot be nil' unless error
|
49
|
+
|
50
|
+
os = nil
|
51
|
+
@gate.synchronize do
|
52
|
+
check_disposed
|
53
|
+
|
54
|
+
unless @stopped
|
55
|
+
os = @observers.clone
|
56
|
+
@observers = []
|
57
|
+
@stopped = true
|
58
|
+
@error = error
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
os.each {|o| o.on_error error } if os
|
63
|
+
end
|
64
|
+
|
65
|
+
# Notifies all subscribed observers with the value.
|
66
|
+
def on_next(value)
|
67
|
+
os = nil
|
68
|
+
@gate.synchronize do
|
69
|
+
check_disposed
|
70
|
+
os = @observers.clone unless @stopped
|
71
|
+
end
|
72
|
+
|
73
|
+
os.each {|o| o.on_next value } if os
|
74
|
+
end
|
75
|
+
|
76
|
+
# Subscribes an observer to the subject.
|
77
|
+
def subscribe(observer)
|
78
|
+
raise 'observer cannot be nil' unless observer
|
79
|
+
|
80
|
+
@gate.synchronize do
|
81
|
+
check_disposed
|
82
|
+
|
83
|
+
if !@stopped
|
84
|
+
@observers.push(observer)
|
85
|
+
return InnerSubscription.new(self, observer)
|
86
|
+
elsif @error
|
87
|
+
observer.on_error @error
|
88
|
+
return Subscription.empty
|
89
|
+
else
|
90
|
+
observer.on_completed
|
91
|
+
return Subscription.empty
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# Unsubscribe all observers and release resources.
|
97
|
+
def unsubscribe
|
98
|
+
@gate.synchronize do
|
99
|
+
@disposed = true
|
100
|
+
@observers = nil
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
class InnerSubscription
|
105
|
+
def initialize(subject, observer)
|
106
|
+
@subject = subject
|
107
|
+
@observer = observer
|
108
|
+
end
|
109
|
+
|
110
|
+
def unsubscribe
|
111
|
+
if @observer
|
112
|
+
@subject.send(:unsubscribe_observer, @observer)
|
113
|
+
@subject = nil
|
114
|
+
@observer = nil
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
private
|
120
|
+
|
121
|
+
def unsubscribe_observer(observer)
|
122
|
+
@gate.synchronize do
|
123
|
+
@observers.delete(observer) if @observers
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def check_disposed
|
128
|
+
raise ArgumentError.new 'Subject disposed' if @disposed
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
2
|
+
|
3
|
+
require 'rx_ruby/core/observer'
|
4
|
+
require 'rx_ruby/core/observable'
|
5
|
+
|
6
|
+
module RxRuby
|
7
|
+
|
8
|
+
# Provides a set of static methods for creating subjects.
|
9
|
+
class Subject
|
10
|
+
|
11
|
+
# Creates a subject from the specified observer and observable.
|
12
|
+
def self.create(observer, observable)
|
13
|
+
AnonymousSubject.new(observer, observable)
|
14
|
+
end
|
15
|
+
|
16
|
+
class AnonymousSubject
|
17
|
+
include Observable
|
18
|
+
include Observer
|
19
|
+
|
20
|
+
def initialize(observer, observable)
|
21
|
+
@observer = observer
|
22
|
+
@observable = observable
|
23
|
+
end
|
24
|
+
|
25
|
+
def on_completed
|
26
|
+
@observer.on_completed
|
27
|
+
end
|
28
|
+
|
29
|
+
def on_error(error)
|
30
|
+
raise 'error cannot be nil' unless error
|
31
|
+
@observer.on_error(error)
|
32
|
+
end
|
33
|
+
|
34
|
+
def on_next(value)
|
35
|
+
@observer.on_next(value)
|
36
|
+
end
|
37
|
+
|
38
|
+
def subscribe(observer)
|
39
|
+
raise 'observer cannot be nil' unless observer
|
40
|
+
@observable.subscribe(observer)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
2
|
+
|
3
|
+
require 'thread'
|
4
|
+
|
5
|
+
module RxRuby
|
6
|
+
|
7
|
+
# Represents a group of subscription resources that are unsubscribed together.
|
8
|
+
class CompositeSubscription
|
9
|
+
|
10
|
+
include Enumerable
|
11
|
+
|
12
|
+
attr_reader :length
|
13
|
+
|
14
|
+
def initialize(subscriptions = [])
|
15
|
+
@subscriptions = subscriptions
|
16
|
+
@length = subscriptions.length
|
17
|
+
@unsubscribed = false
|
18
|
+
@gate = Mutex.new
|
19
|
+
end
|
20
|
+
|
21
|
+
# Gets a value that indicates whether the object is unsubscribed.
|
22
|
+
def unsubscribed?
|
23
|
+
@unsubscribed
|
24
|
+
end
|
25
|
+
|
26
|
+
def each(&block)
|
27
|
+
@subscriptions.each(&block)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Unsubscribes all subscriptions in the group and removes them from the group.
|
31
|
+
def unsubscribe
|
32
|
+
currentSubscriptions = nil
|
33
|
+
|
34
|
+
@gate.synchronize do
|
35
|
+
unless @unsubscribed
|
36
|
+
@unsubscribed = true
|
37
|
+
currentSubscriptions = @subscriptions
|
38
|
+
@subscriptions = []
|
39
|
+
@length = 0
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
currentSubscriptions.each {|subscription| subscription.unsubscribe} if currentSubscriptions
|
44
|
+
end
|
45
|
+
|
46
|
+
# Adds a subscription to the CompositeSubscription or unsubscribes the subscription if the CompositeSubscription is unsubscribed.
|
47
|
+
def push(subscription)
|
48
|
+
should_unsubscribe = false
|
49
|
+
|
50
|
+
@gate.synchronize do
|
51
|
+
should_unsubscribe = @unsubscribed
|
52
|
+
|
53
|
+
unless @unsubscribed
|
54
|
+
@subscriptions.push(subscription)
|
55
|
+
@length += 1
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
subscription.unsubscribe if should_unsubscribe
|
60
|
+
|
61
|
+
return self
|
62
|
+
end
|
63
|
+
alias_method :<<, :push
|
64
|
+
|
65
|
+
# Removes and unsubscribes all subscriptions from the CompositeSubscription, but does not dispose the CompositeSubscription.
|
66
|
+
def clear
|
67
|
+
currentSubscriptions = nil
|
68
|
+
|
69
|
+
@gate.synchronize do
|
70
|
+
currentSubscriptions = @subscriptions
|
71
|
+
@subscriptions = []
|
72
|
+
@length = 0
|
73
|
+
end
|
74
|
+
currentSubscriptions.each {|subscription| subscription.unsubscribe}
|
75
|
+
end
|
76
|
+
|
77
|
+
# Removes and unsubscribes the first occurrence of a subscription from the CompositeSubscription.
|
78
|
+
def delete(subscription)
|
79
|
+
should_unsubscribe = nil
|
80
|
+
|
81
|
+
@gate.synchronize do
|
82
|
+
should_unsubscribe = @subscriptions.delete(subscription)
|
83
|
+
@length -= 1 if should_unsubscribe
|
84
|
+
end
|
85
|
+
|
86
|
+
subscription.unsubscribe if should_unsubscribe
|
87
|
+
|
88
|
+
should_unsubscribe
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
2
|
+
|
3
|
+
require 'thread'
|
4
|
+
require 'rx_ruby/subscriptions/subscription'
|
5
|
+
|
6
|
+
module RxRuby
|
7
|
+
|
8
|
+
# Represents a subscription resource that only disposes its underlying subscription resource when all dependent subscription objects have been unsubscribed.
|
9
|
+
class RefCountSubscription
|
10
|
+
|
11
|
+
def initialize(subscription)
|
12
|
+
raise ArgumentError.new 'Subscription cannot be nil' unless subscription
|
13
|
+
|
14
|
+
@subscription = subscription
|
15
|
+
@primary_unsubscribed = false
|
16
|
+
@gate = Mutex.new
|
17
|
+
@count = 0
|
18
|
+
end
|
19
|
+
|
20
|
+
# Gets a value that indicates whether the object is disposed.
|
21
|
+
def unsubscribed?
|
22
|
+
@subscription.nil?
|
23
|
+
end
|
24
|
+
|
25
|
+
# Returns a dependent subscription that when disposed decreases the refcount on the underlying subscription.
|
26
|
+
def subscription
|
27
|
+
@gate.synchronize do
|
28
|
+
if @subscription
|
29
|
+
@count += 1
|
30
|
+
return InnerSubscription.new self
|
31
|
+
else
|
32
|
+
return Subscription.empty
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Unsubscribes the underlying subscription only when all dependent subscriptions have been unsubscribed.
|
38
|
+
def unsubscribe
|
39
|
+
subscription = nil
|
40
|
+
@gate.synchronize do
|
41
|
+
if @subscription
|
42
|
+
unless @primary_unsubscribed
|
43
|
+
@primary_unsubscribed = true
|
44
|
+
|
45
|
+
if @count == 0
|
46
|
+
subscription = @subscription
|
47
|
+
@subscription = nil
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
subscription.unsubscribe if subscription
|
54
|
+
end
|
55
|
+
|
56
|
+
def release
|
57
|
+
subscription = nil
|
58
|
+
@gate.synchronize do
|
59
|
+
if @subscription
|
60
|
+
@count -= 1
|
61
|
+
|
62
|
+
if @primary_unsubscribed && @count == 0
|
63
|
+
subscription = @subscription
|
64
|
+
@subscription = nil
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
subscription.unsubscribe if subscription
|
70
|
+
end
|
71
|
+
|
72
|
+
class InnerSubscription
|
73
|
+
def initialize(parent)
|
74
|
+
@parent = parent
|
75
|
+
end
|
76
|
+
|
77
|
+
def unsubscribe
|
78
|
+
parent = nil
|
79
|
+
Mutex.new.synchronize do
|
80
|
+
parent = @parent
|
81
|
+
@parent = nil
|
82
|
+
end
|
83
|
+
parent.release if parent
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
2
|
+
|
3
|
+
module RxRuby
|
4
|
+
# Represents a disposable resource whose disposal invocation will be scheduled on the specified scheduler
|
5
|
+
class ScheduledDisposable
|
6
|
+
|
7
|
+
attr_reader :scheduler, :subscription
|
8
|
+
|
9
|
+
def initialize(scheduler, subscription)
|
10
|
+
raise 'disposable cannot be nil' unless subscription
|
11
|
+
raise 'scheduler cannot be nil' unless scheduler
|
12
|
+
|
13
|
+
@scheduler = scheduler
|
14
|
+
@subscription = subscription
|
15
|
+
end
|
16
|
+
|
17
|
+
# Gets a value that indicates whether the object is unsubscribed.
|
18
|
+
def unsubscribed?
|
19
|
+
@subscription.nil?
|
20
|
+
end
|
21
|
+
|
22
|
+
# Unsubscribes the wrapped subscription on the provided scheduler.
|
23
|
+
def unsubscribe
|
24
|
+
@scheduler.schedule lambda do
|
25
|
+
unless @subscription.nil?
|
26
|
+
@subscription.unsubscribe
|
27
|
+
@subscription = nil
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
2
|
+
|
3
|
+
require 'thread'
|
4
|
+
|
5
|
+
module RxRuby
|
6
|
+
|
7
|
+
# Represents a subscription resource whose underlying subscription resource can be replaced by another subscription resource, causing automatic disposal of the previous underlying subscription resource.
|
8
|
+
class SerialSubscription
|
9
|
+
include Subscription
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@gate = Mutex.new
|
13
|
+
@current = nil
|
14
|
+
@unsubscribed = false
|
15
|
+
end
|
16
|
+
|
17
|
+
# Gets a value that indicates whether the object is unsubscribed.
|
18
|
+
def unsubscribed?
|
19
|
+
@gate.synchronize do
|
20
|
+
return @unsubscribed
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Gets the underlying subscription.
|
25
|
+
def subscription
|
26
|
+
@current
|
27
|
+
end
|
28
|
+
|
29
|
+
# Sets the underlying subscription.
|
30
|
+
def subscription=(new_subscription)
|
31
|
+
should_unsubscribe = false
|
32
|
+
old = nil
|
33
|
+
@gate.synchronize do
|
34
|
+
should_unsubscribe = @unsubscribed
|
35
|
+
unless should_unsubscribe
|
36
|
+
old = @current
|
37
|
+
@current = new_subscription
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
old.unsubscribe if old
|
42
|
+
new_subscription.unsubscribe if should_unsubscribe && !new_subscription.nil?
|
43
|
+
end
|
44
|
+
|
45
|
+
# Unsubscribes the current underlying subscription and all future subscriptions.
|
46
|
+
def unsubscribe
|
47
|
+
old = nil
|
48
|
+
@gate.synchronize do
|
49
|
+
unless @unsubscribed
|
50
|
+
@unsubscribed = true
|
51
|
+
old = @current
|
52
|
+
@current = nil
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
old.unsubscribe if old
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|