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,104 @@
|
|
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/concurrency/current_thread_scheduler'
|
4
|
+
require 'rx_ruby/concurrency/immediate_scheduler'
|
5
|
+
require 'rx_ruby/core/observer'
|
6
|
+
require 'rx_ruby/core/auto_detach_observer'
|
7
|
+
require 'rx_ruby/subscriptions/subscription'
|
8
|
+
|
9
|
+
module RxRuby
|
10
|
+
|
11
|
+
module Observable
|
12
|
+
|
13
|
+
def subscribe(*args)
|
14
|
+
case args.size
|
15
|
+
when 0
|
16
|
+
if block_given?
|
17
|
+
_subscribe Observer.configure {|o| o.on_next(&Proc.new) }
|
18
|
+
else
|
19
|
+
_subscribe Observer.configure
|
20
|
+
end
|
21
|
+
when 1
|
22
|
+
_subscribe args[0]
|
23
|
+
when 3
|
24
|
+
_subscribe Observer.configure {|o|
|
25
|
+
o.on_next(&args[0])
|
26
|
+
o.on_error(&args[1])
|
27
|
+
o.on_completed(&args[2])
|
28
|
+
}
|
29
|
+
else
|
30
|
+
raise ArgumentError, "wrong number of arguments (#{args.size} for 0..1 or 3)"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Subscribes the given observer to the observable sequence.
|
35
|
+
# @param [Observer] observer
|
36
|
+
# @return [Subscription]
|
37
|
+
def _subscribe(observer)
|
38
|
+
|
39
|
+
auto_detach_observer = AutoDetachObserver.new observer
|
40
|
+
|
41
|
+
if CurrentThreadScheduler.schedule_required?
|
42
|
+
CurrentThreadScheduler.instance.schedule_with_state auto_detach_observer, method(:schedule_subscribe)
|
43
|
+
else
|
44
|
+
begin
|
45
|
+
auto_detach_observer.subscription = subscribe_core auto_detach_observer
|
46
|
+
rescue => e
|
47
|
+
raise e unless auto_detach_observer.fail e
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
auto_detach_observer
|
52
|
+
end
|
53
|
+
|
54
|
+
# Subscribes the given block to the on_next action of the observable sequence.
|
55
|
+
# @param [Object] block
|
56
|
+
# @return [Subscription]
|
57
|
+
def subscribe_on_next(&block)
|
58
|
+
raise ArgumentError.new 'Block is required' unless block_given?
|
59
|
+
subscribe(Observer.configure {|o| o.on_next(&block) })
|
60
|
+
end
|
61
|
+
|
62
|
+
# Subscribes the given block to the on_error action of the observable sequence.
|
63
|
+
def subscribe_on_error(&block)
|
64
|
+
raise ArgumentError.new 'Block is required' unless block_given?
|
65
|
+
subscribe(Observer.configure {|o| o.on_error(&block) })
|
66
|
+
end
|
67
|
+
|
68
|
+
# Subscribes the given block to the on_completed action of the observable sequence.
|
69
|
+
def subscribe_on_completed(&block)
|
70
|
+
raise ArgumentError.new 'Block is required' unless block_given?
|
71
|
+
subscribe(Observer.configure {|o| o.on_completed(&block) })
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def schedule_subscribe(_, auto_detach_observer)
|
77
|
+
begin
|
78
|
+
auto_detach_observer.subscription = subscribe_core auto_detach_observer
|
79
|
+
rescue => e
|
80
|
+
raise e unless auto_detach_observer.fail e
|
81
|
+
end
|
82
|
+
|
83
|
+
Subscription.empty
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
class AnonymousObservable
|
89
|
+
|
90
|
+
include Observable
|
91
|
+
|
92
|
+
def initialize(&subscribe)
|
93
|
+
@subscribe = subscribe
|
94
|
+
end
|
95
|
+
|
96
|
+
protected
|
97
|
+
|
98
|
+
def subscribe_core(obs)
|
99
|
+
@subscribe.call(obs) || Subscription.empty
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
@@ -0,0 +1,50 @@
|
|
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/scheduled_observer'
|
5
|
+
|
6
|
+
module RxRuby
|
7
|
+
|
8
|
+
module Observer
|
9
|
+
# Schedules the invocation of observer methods on the given scheduler.
|
10
|
+
def notify_on(scheduler)
|
11
|
+
ObserveOnObserver.new(scheduler, self, nil)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class ObserveOnObserver < ScheduledObserver
|
16
|
+
|
17
|
+
def initialize(scheduler, observer, cancel = nil)
|
18
|
+
@cancel = cancel
|
19
|
+
|
20
|
+
super(scheduler, observer)
|
21
|
+
end
|
22
|
+
|
23
|
+
def on_next_core(value)
|
24
|
+
ensure_active
|
25
|
+
super(value)
|
26
|
+
end
|
27
|
+
|
28
|
+
def on_error_core(error)
|
29
|
+
ensure_active
|
30
|
+
super(error)
|
31
|
+
end
|
32
|
+
|
33
|
+
def on_completed_core
|
34
|
+
ensure_active
|
35
|
+
super
|
36
|
+
end
|
37
|
+
|
38
|
+
def unsubscribe
|
39
|
+
super
|
40
|
+
|
41
|
+
cancel = nil
|
42
|
+
Mutex.new.synchronize do
|
43
|
+
cancel = @cancel
|
44
|
+
@cancel = nil
|
45
|
+
end
|
46
|
+
|
47
|
+
canel.unsubscribe if cancel
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,119 @@
|
|
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
|
+
|
5
|
+
# Configuration class for storing Observer actions
|
6
|
+
class ObserverConfiguration
|
7
|
+
|
8
|
+
DEFAULT_ON_NEXT = lambda {|x| }
|
9
|
+
DEFAULT_ON_ERROR = lambda {|error| raise error }
|
10
|
+
DEFAULT_ON_COMPLETED = lambda { }
|
11
|
+
|
12
|
+
attr_reader :on_next_action, :on_error_action, :on_completed_action
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@on_next_action = DEFAULT_ON_NEXT
|
16
|
+
@on_error_action = DEFAULT_ON_ERROR
|
17
|
+
@on_completed_action = DEFAULT_ON_COMPLETED
|
18
|
+
end
|
19
|
+
|
20
|
+
def on_next(&on_next_action)
|
21
|
+
@on_next_action = on_next_action
|
22
|
+
end
|
23
|
+
|
24
|
+
def on_error(&on_error_action)
|
25
|
+
@on_error_action = on_error_action
|
26
|
+
end
|
27
|
+
|
28
|
+
def on_completed(&on_completed_action)
|
29
|
+
@on_completed_action = on_completed_action
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Module for all Observers
|
34
|
+
module Observer
|
35
|
+
|
36
|
+
# Hides the identity of an observer.
|
37
|
+
def as_observer
|
38
|
+
Observer.configure do |o|
|
39
|
+
o.on_next(&method(:on_next))
|
40
|
+
o.on_error(&method(:on_error))
|
41
|
+
o.on_completed(&method(:on_completed))
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Creates a notification callback from an observer.
|
46
|
+
def to_notifier
|
47
|
+
lambda {|n| n.accept self}
|
48
|
+
end
|
49
|
+
|
50
|
+
class << self
|
51
|
+
|
52
|
+
# Configures a new instance of an Observer
|
53
|
+
def configure
|
54
|
+
config = ObserverConfiguration.new
|
55
|
+
yield config if block_given?
|
56
|
+
ObserverBase.new config
|
57
|
+
end
|
58
|
+
|
59
|
+
def create(on_next = nil, on_error = nil, on_completed = nil)
|
60
|
+
configure do |o|
|
61
|
+
o.on_next(&on_next) if on_next
|
62
|
+
o.on_error(&on_error) if on_error
|
63
|
+
o.on_completed(&on_completed) if on_completed
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
# Base class for all Observer implementations
|
71
|
+
class ObserverBase
|
72
|
+
include Observer
|
73
|
+
|
74
|
+
def initialize(config)
|
75
|
+
@config = config
|
76
|
+
@stopped = false
|
77
|
+
end
|
78
|
+
|
79
|
+
# Unsubscribes from the current observer causing it to transition to the stopped state.
|
80
|
+
def unsubscribe
|
81
|
+
@stopped = true
|
82
|
+
end
|
83
|
+
|
84
|
+
def dispose
|
85
|
+
unsubscribe
|
86
|
+
end
|
87
|
+
|
88
|
+
# Notifies the observer of a new element in the sequence.
|
89
|
+
def on_next(value)
|
90
|
+
@config.on_next_action.call value unless @stopped
|
91
|
+
end
|
92
|
+
|
93
|
+
# Notifies the observer that an exception has occurred.
|
94
|
+
def on_error(error)
|
95
|
+
raise 'Error cannot be nil' unless error
|
96
|
+
unless @stopped
|
97
|
+
@stopped = true
|
98
|
+
@config.on_error_action.call error
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# Notifies the observer of the end of the sequence.
|
103
|
+
def on_completed
|
104
|
+
unless @stopped
|
105
|
+
@stopped = true
|
106
|
+
@config.on_completed_action.call
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def fail(error)
|
111
|
+
unless @stopped
|
112
|
+
@stopped = true
|
113
|
+
@config.on_error_action.call error
|
114
|
+
return true
|
115
|
+
end
|
116
|
+
return false
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
2
|
+
|
3
|
+
require 'monitor'
|
4
|
+
require 'rx_ruby/subscriptions/serial_subscription'
|
5
|
+
require 'rx_ruby/core/observer'
|
6
|
+
|
7
|
+
module RxRuby
|
8
|
+
|
9
|
+
class ScheduledObserver < ObserverBase
|
10
|
+
|
11
|
+
def initialize(scheduler, observer)
|
12
|
+
@scheduler = scheduler
|
13
|
+
@observer = observer
|
14
|
+
@gate = Monitor.new
|
15
|
+
@queue = []
|
16
|
+
@subscriber = SerialSubscription.new
|
17
|
+
@acquired = false
|
18
|
+
@faulted = false
|
19
|
+
|
20
|
+
config = ObserverConfiguration.new
|
21
|
+
config.on_next(&method(:on_next_core))
|
22
|
+
config.on_error(&method(:on_error_core))
|
23
|
+
config.on_completed(&method(:on_completed_core))
|
24
|
+
|
25
|
+
super(config)
|
26
|
+
end
|
27
|
+
|
28
|
+
def on_next_core(value)
|
29
|
+
@gate.synchronize { @queue.push(lambda { @observer.on_next value }) }
|
30
|
+
end
|
31
|
+
|
32
|
+
def on_error_core(error)
|
33
|
+
@gate.synchronize { @queue.push(lambda { @observer.on_error error }) }
|
34
|
+
end
|
35
|
+
|
36
|
+
def on_completed_core
|
37
|
+
@gate.synchronize { @queue.push(lambda { @observer.on_completed }) }
|
38
|
+
end
|
39
|
+
|
40
|
+
def ensure_active(n=0)
|
41
|
+
owner = false
|
42
|
+
|
43
|
+
@gate.synchronize do
|
44
|
+
if !@faulted && @queue.length > 0
|
45
|
+
owner = !@acquired
|
46
|
+
@acquired = true
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
@subscriber.subscription = @scheduler.schedule_recursive_with_state(nil, method(:run)) if owner
|
51
|
+
end
|
52
|
+
|
53
|
+
def run(state, recurse)
|
54
|
+
work = nil
|
55
|
+
@gate.synchronize do
|
56
|
+
if @queue.length > 0
|
57
|
+
work = @queue.shift
|
58
|
+
else
|
59
|
+
@acquired = false
|
60
|
+
return
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
begin
|
65
|
+
work.call
|
66
|
+
rescue => e
|
67
|
+
@queue = []
|
68
|
+
@faulted = true
|
69
|
+
|
70
|
+
raise e
|
71
|
+
end
|
72
|
+
|
73
|
+
recurse.call state
|
74
|
+
end
|
75
|
+
|
76
|
+
def unsubscribe
|
77
|
+
super
|
78
|
+
@subscriber.unsubscribe
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
2
|
+
|
3
|
+
require 'monitor'
|
4
|
+
require 'rx_ruby/core/observer'
|
5
|
+
|
6
|
+
module RxRuby
|
7
|
+
|
8
|
+
module Observer
|
9
|
+
|
10
|
+
class << self
|
11
|
+
# Synchronizes access to the observer such that its callback methods cannot be called concurrently by multiple threads, using the specified gate object for use by a Monitor based lock.
|
12
|
+
# This overload is useful when coordinating multiple observers that access shared state by synchronizing on a common gate object if given.
|
13
|
+
# Notice reentrant observer callbacks on the same thread are still possible.
|
14
|
+
def allow_reentrancy(observer, gate = Monitor.new)
|
15
|
+
SynchronizedObserver.new(observer, gate)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class SynchronizedObserver < RxRuby::ObserverBase
|
21
|
+
|
22
|
+
def on_next_core(value)
|
23
|
+
@gate.synchronize { @observer.on_next value }
|
24
|
+
end
|
25
|
+
|
26
|
+
def on_error_core(error)
|
27
|
+
@gate.synchronize { @observer.on_error error }
|
28
|
+
end
|
29
|
+
|
30
|
+
def on_completed_core
|
31
|
+
@gate.synchronize { @observer.on_completed }
|
32
|
+
end
|
33
|
+
|
34
|
+
def initialize(observer, gate)
|
35
|
+
@observer = observer
|
36
|
+
@gate = gate
|
37
|
+
|
38
|
+
config = ObserverConfiguration.new
|
39
|
+
config.on_next(&method(:on_next_core))
|
40
|
+
config.on_error(&method(:on_error_core))
|
41
|
+
config.on_completed(&method(:on_completed_core))
|
42
|
+
|
43
|
+
super(config)
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,17 @@
|
|
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
|
+
|
5
|
+
# Record of a value including the virtual time it was produced on.
|
6
|
+
class TimeInterval < Struct.new(:interval, :value)
|
7
|
+
|
8
|
+
def initialize(interval, value)
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_s
|
13
|
+
"(#{value})@(#{interval})"
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,122 @@
|
|
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
|
+
|
5
|
+
# Priority Queue implemented as a binary heap.
|
6
|
+
class PriorityQueue
|
7
|
+
def initialize
|
8
|
+
@items = []
|
9
|
+
@mutex = Mutex.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def peek
|
13
|
+
@mutex.synchronize do
|
14
|
+
unsafe_peek
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def shift
|
19
|
+
@mutex.synchronize do
|
20
|
+
result = unsafe_peek
|
21
|
+
delete_at 0
|
22
|
+
result
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def push(item)
|
27
|
+
@mutex.synchronize do
|
28
|
+
@items.push IndexedItem.new(item)
|
29
|
+
percolate length - 1
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def delete(item)
|
34
|
+
@mutex.synchronize do
|
35
|
+
index = @items.index {|it| it.value == item }
|
36
|
+
if index
|
37
|
+
delete_at index
|
38
|
+
true
|
39
|
+
else
|
40
|
+
false
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def length
|
46
|
+
@items.length
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def unsafe_peek
|
52
|
+
@items.first.value unless @items.empty?
|
53
|
+
end
|
54
|
+
|
55
|
+
def delete_at(index)
|
56
|
+
substitute = @items.pop
|
57
|
+
if substitute and index < @items.length
|
58
|
+
@items[index] = substitute
|
59
|
+
heapify index
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# bubble up an item while it's smaller than parents
|
64
|
+
def percolate(index)
|
65
|
+
parent = (index - 1) / 2
|
66
|
+
return if parent < 0
|
67
|
+
|
68
|
+
current_value = @items[index]
|
69
|
+
parent_value = @items[parent]
|
70
|
+
|
71
|
+
if current_value < parent_value
|
72
|
+
@items[index] = parent_value
|
73
|
+
@items[parent] = current_value
|
74
|
+
percolate parent
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# bubble down an item while it's bigger than children
|
79
|
+
def heapify(index)
|
80
|
+
current_index = index
|
81
|
+
left_index = 2 * index + 1
|
82
|
+
right_index = 2 * index + 2
|
83
|
+
|
84
|
+
current_value = @items[index]
|
85
|
+
left_value = @items[left_index]
|
86
|
+
right_value = @items[right_index]
|
87
|
+
|
88
|
+
if right_value && right_value < current_value && right_value < left_value
|
89
|
+
current_index = right_index
|
90
|
+
elsif left_value && left_value < current_value
|
91
|
+
current_index = left_index
|
92
|
+
end
|
93
|
+
|
94
|
+
if current_index != index
|
95
|
+
@items[index] = @items[current_index]
|
96
|
+
@items[current_index] = current_value
|
97
|
+
heapify current_index
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
class IndexedItem
|
102
|
+
include Comparable
|
103
|
+
attr_reader :id , :value
|
104
|
+
|
105
|
+
@@length = 0
|
106
|
+
|
107
|
+
def initialize(value)
|
108
|
+
@id = @@length += 1
|
109
|
+
@value = value
|
110
|
+
end
|
111
|
+
|
112
|
+
def <=>(other)
|
113
|
+
if @value == other.value
|
114
|
+
@id <=> other.id
|
115
|
+
else
|
116
|
+
@value <=> other.value
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
end
|