├── .gitattributes
├── .gitignore
├── .travis.yml
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── benchmarks
└── subject-put
│ ├── .gitignore
│ ├── dub.json
│ └── source
│ └── app.d
├── deps-lock.txt
├── deps.dot
├── deps.png
├── deps.svg
├── deps.txt
├── docs.json
├── docs
├── articles
│ ├── Overview.ja.md
│ └── Practice.ja.md
├── index.html
├── rx.algorithm.all.all.1.html
├── rx.algorithm.all.all.2.html
├── rx.algorithm.all.all.html
├── rx.algorithm.all.html
├── rx.algorithm.any.any.1.html
├── rx.algorithm.any.any.2.html
├── rx.algorithm.any.any.html
├── rx.algorithm.any.html
├── rx.algorithm.buffer.buffered.html
├── rx.algorithm.buffer.html
├── rx.algorithm.combineLatest.combineLatest.html
├── rx.algorithm.combineLatest.html
├── rx.algorithm.debounce.debounce.1.html
├── rx.algorithm.debounce.debounce.2.html
├── rx.algorithm.debounce.debounce.html
├── rx.algorithm.debounce.html
├── rx.algorithm.filter.FilterObservable.html
├── rx.algorithm.filter.FilterObservable.subscribe.html
├── rx.algorithm.filter.FilterObservable.this.html
├── rx.algorithm.filter.filter.html
├── rx.algorithm.filter.html
├── rx.algorithm.fold.fold.html
├── rx.algorithm.fold.html
├── rx.algorithm.groupby.GroupedObservable.html
├── rx.algorithm.groupby.groupBy.html
├── rx.algorithm.groupby.html
├── rx.algorithm.html
├── rx.algorithm.map.html
├── rx.algorithm.map.map.html
├── rx.algorithm.merge.html
├── rx.algorithm.merge.merge.1.html
├── rx.algorithm.merge.merge.2.html
├── rx.algorithm.merge.merge.html
├── rx.algorithm.scan.html
├── rx.algorithm.scan.scan.html
├── rx.algorithm.tee.html
├── rx.algorithm.tee.tee.html
├── rx.algorithm.uniq.distinctUntilChanged.html
├── rx.algorithm.uniq.html
├── rx.algorithm.uniq.uniq.html
├── rx.disposable.AnonymousDisposable.dispose.html
├── rx.disposable.AnonymousDisposable.html
├── rx.disposable.AnonymousDisposable.this.html
├── rx.disposable.Cancelable.html
├── rx.disposable.Cancelable.isDisposed.html
├── rx.disposable.CancelableObject.html
├── rx.disposable.CancelableObject.isDisposed.html
├── rx.disposable.CancelableObject.this.html
├── rx.disposable.CancellationToken.cancel.html
├── rx.disposable.CancellationToken.dispose.html
├── rx.disposable.CancellationToken.html
├── rx.disposable.CancellationToken.isCanceled.html
├── rx.disposable.CancellationToken.isDisposed.html
├── rx.disposable.CompositeDisposable.dispose.html
├── rx.disposable.CompositeDisposable.html
├── rx.disposable.CompositeDisposable.this.html
├── rx.disposable.Disposable.dispose.html
├── rx.disposable.Disposable.html
├── rx.disposable.DisposableObject.dispose.html
├── rx.disposable.DisposableObject.html
├── rx.disposable.DisposableObject.this.html
├── rx.disposable.NopDisposable.html
├── rx.disposable.NopDisposable.instance.html
├── rx.disposable.RefCountDisposable.dispose.html
├── rx.disposable.RefCountDisposable.getDisposable.html
├── rx.disposable.RefCountDisposable.html
├── rx.disposable.RefCountDisposable.this.html
├── rx.disposable.SerialDisposable.disposable.1.html
├── rx.disposable.SerialDisposable.disposable.2.html
├── rx.disposable.SerialDisposable.disposable.html
├── rx.disposable.SerialDisposable.dispose.html
├── rx.disposable.SerialDisposable.html
├── rx.disposable.SerialDisposable.isDisposed.html
├── rx.disposable.SignalDisposable.dispose.html
├── rx.disposable.SignalDisposable.html
├── rx.disposable.SignalDisposable.signal.html
├── rx.disposable.SingleAssignmentDisposable.dispose.html
├── rx.disposable.SingleAssignmentDisposable.html
├── rx.disposable.SingleAssignmentDisposable.isDisposed.html
├── rx.disposable.SingleAssignmentDisposable.setDisposable.html
├── rx.disposable.html
├── rx.disposable.isCancelable.html
├── rx.disposable.isDisposable.html
├── rx.disposable.withDisposed.1.html
├── rx.disposable.withDisposed.2.html
├── rx.disposable.withDisposed.html
├── rx.html
├── rx.observable.Observable.html
├── rx.observable.ObservableObject.html
├── rx.observable.asObservable.html
├── rx.observable.defer.html
├── rx.observable.doSubscribe.1.html
├── rx.observable.doSubscribe.2.html
├── rx.observable.doSubscribe.3.html
├── rx.observable.doSubscribe.4.html
├── rx.observable.doSubscribe.5.html
├── rx.observable.doSubscribe.html
├── rx.observable.empty.html
├── rx.observable.error.html
├── rx.observable.from.html
├── rx.observable.html
├── rx.observable.isObservable.1.html
├── rx.observable.isObservable.2.html
├── rx.observable.isObservable.html
├── rx.observable.isSubscribable.html
├── rx.observable.never.html
├── rx.observer.CompositeObserver.add.html
├── rx.observer.CompositeObserver.completed.html
├── rx.observer.CompositeObserver.empty.html
├── rx.observer.CompositeObserver.failure.html
├── rx.observer.CompositeObserver.html
├── rx.observer.CompositeObserver.observers.html
├── rx.observer.CompositeObserver.put.html
├── rx.observer.CompositeObserver.remove.html
├── rx.observer.CompositeObserver.removeStrict.html
├── rx.observer.CompositeObserver.this.html
├── rx.observer.DoneObserver.html
├── rx.observer.NopObserver.html
├── rx.observer.NopObserver.instance.html
├── rx.observer.Observer.completed.html
├── rx.observer.Observer.failure.html
├── rx.observer.Observer.html
├── rx.observer.ObserverObject.completed.html
├── rx.observer.ObserverObject.failure.html
├── rx.observer.ObserverObject.html
├── rx.observer.hasCompleted.html
├── rx.observer.hasFailure.html
├── rx.observer.html
├── rx.observer.isObserver.html
├── rx.observer.makeObserver.1.html
├── rx.observer.makeObserver.2.html
├── rx.observer.makeObserver.3.html
├── rx.observer.makeObserver.html
├── rx.range.drop.drop.html
├── rx.range.drop.html
├── rx.range.html
├── rx.range.take.html
├── rx.range.take.take.html
├── rx.range.takeLast.html
├── rx.range.takeLast.takeLast.html
├── rx.range.takeUntil.html
├── rx.range.takeUntil.takeUntil.html
├── rx.range.zip.GetElementsTuple.html
├── rx.range.zip.GetZipStoreType.html
├── rx.range.zip.GetZipStoreTypeImpl.GetZipStoreTypeImpl.html
├── rx.range.zip.GetZipStoreTypeImpl.html
├── rx.range.zip.ZipNObservable.ElementType.html
├── rx.range.zip.ZipNObservable.html
├── rx.range.zip.ZipNObservable.subscribe.html
├── rx.range.zip.ZipNObservable.this.html
├── rx.range.zip.ZipStore.html
├── rx.range.zip.html
├── rx.range.zip.zip.html
├── rx.scheduler.AsyncScheduler.html
├── rx.scheduler.AsyncScheduler.schedule.html
├── rx.scheduler.HistoricalScheduler.html
├── rx.scheduler.HistoricalScheduler.schedule.html
├── rx.scheduler.HistoricalScheduler.start.html
├── rx.scheduler.HistoricalScheduler.this.html
├── rx.scheduler.LocalScheduler.html
├── rx.scheduler.LocalScheduler.start.html
├── rx.scheduler.MostDerivedScheduler.MostDerivedScheduler.1.html
├── rx.scheduler.MostDerivedScheduler.MostDerivedScheduler.2.html
├── rx.scheduler.MostDerivedScheduler.MostDerivedScheduler.html
├── rx.scheduler.MostDerivedScheduler.html
├── rx.scheduler.ObserveOnObservable.html
├── rx.scheduler.ObserveOnObservable.subscribe.html
├── rx.scheduler.ObserveOnObservable.this.html
├── rx.scheduler.ObserveOnObserver.completed.html
├── rx.scheduler.ObserveOnObserver.failure.html
├── rx.scheduler.ObserveOnObserver.html
├── rx.scheduler.ObserveOnObserver.put.html
├── rx.scheduler.ObserveOnObserver.this.1.html
├── rx.scheduler.ObserveOnObserver.this.2.html
├── rx.scheduler.ObserveOnObserver.this.html
├── rx.scheduler.Scheduler.html
├── rx.scheduler.Scheduler.start.html
├── rx.scheduler.SchedulerObject.html
├── rx.scheduler.SchedulerObject.schedule.html
├── rx.scheduler.SchedulerObject.start.html
├── rx.scheduler.SchedulerObject.this.1.html
├── rx.scheduler.SchedulerObject.this.2.html
├── rx.scheduler.SchedulerObject.this.html
├── rx.scheduler.SubscribeOnObservable.html
├── rx.scheduler.SubscribeOnObservable.subscribe.html
├── rx.scheduler.SubscribeOnObservable.this.html
├── rx.scheduler.TaskPoolScheduler.html
├── rx.scheduler.TaskPoolScheduler.schedule.html
├── rx.scheduler.TaskPoolScheduler.start.html
├── rx.scheduler.TaskPoolScheduler.this.html
├── rx.scheduler.ThreadScheduler.html
├── rx.scheduler.ThreadScheduler.schedule.html
├── rx.scheduler.ThreadScheduler.start.html
├── rx.scheduler.currentScheduler.1.html
├── rx.scheduler.currentScheduler.2.html
├── rx.scheduler.currentScheduler.html
├── rx.scheduler.html
├── rx.scheduler.isAsyncScheduler.html
├── rx.scheduler.isScheduler.html
├── rx.scheduler.observeOn.html
├── rx.scheduler.subscribeOn.html
├── rx.subject.AsyncSubject.completed.html
├── rx.subject.AsyncSubject.failure.html
├── rx.subject.AsyncSubject.html
├── rx.subject.AsyncSubject.put.html
├── rx.subject.AsyncSubject.subscribe.1.html
├── rx.subject.AsyncSubject.subscribe.2.html
├── rx.subject.AsyncSubject.subscribe.html
├── rx.subject.AsyncSubject.unsubscribe.html
├── rx.subject.BehaviorSubject.completed.html
├── rx.subject.BehaviorSubject.failure.html
├── rx.subject.BehaviorSubject.html
├── rx.subject.BehaviorSubject.put.html
├── rx.subject.BehaviorSubject.subscribe.1.html
├── rx.subject.BehaviorSubject.subscribe.2.html
├── rx.subject.BehaviorSubject.subscribe.html
├── rx.subject.BehaviorSubject.this.1.html
├── rx.subject.BehaviorSubject.this.2.html
├── rx.subject.BehaviorSubject.this.html
├── rx.subject.BehaviorSubject.value.1.html
├── rx.subject.BehaviorSubject.value.2.html
├── rx.subject.BehaviorSubject.value.html
├── rx.subject.ReplaySubject.completed.html
├── rx.subject.ReplaySubject.failure.html
├── rx.subject.ReplaySubject.html
├── rx.subject.ReplaySubject.put.html
├── rx.subject.ReplaySubject.subscribe.1.html
├── rx.subject.ReplaySubject.subscribe.2.html
├── rx.subject.ReplaySubject.subscribe.html
├── rx.subject.ReplaySubject.this.html
├── rx.subject.Subject.html
├── rx.subject.SubjectObject.completed.html
├── rx.subject.SubjectObject.failure.html
├── rx.subject.SubjectObject.html
├── rx.subject.SubjectObject.put.html
├── rx.subject.SubjectObject.subscribe.1.html
├── rx.subject.SubjectObject.subscribe.2.html
├── rx.subject.SubjectObject.subscribe.html
├── rx.subject.SubjectObject.this.html
├── rx.subject.SubjectObject.unsubscribe.html
├── rx.subject.asBehaviorSubject.html
├── rx.subject.asReplaySubject.html
├── rx.subject.html
├── rx.util.AtomicCounter.html
├── rx.util.AtomicCounter.isZero.html
├── rx.util.AtomicCounter.this.html
├── rx.util.AtomicCounter.tryDecrement.html
├── rx.util.AtomicCounter.trySetZero.html
├── rx.util.AtomicCounter.tryUpdateCount.html
├── rx.util.EventSignal.html
├── rx.util.EventSignal.setSignal.html
├── rx.util.EventSignal.signal.html
├── rx.util.EventSignal.this.html
├── rx.util.EventSignal.wait.html
├── rx.util.Ticket.html
├── rx.util.TicketBase.html
├── rx.util.TicketBase.isStamped.html
├── rx.util.TicketBase.stamp.html
├── rx.util.assumeThreadLocal.1.html
├── rx.util.assumeThreadLocal.2.html
├── rx.util.assumeThreadLocal.html
├── rx.util.exchange.html
├── rx.util.html
├── script.js
├── search-docs.html
├── search-docs.js
├── search-results.html
└── style.css
├── dub.json
├── dub.selections.json
├── examples
├── concurrency
│ ├── .gitignore
│ ├── dub.json
│ └── source
│ │ └── app.d
├── fizzbuzz
│ ├── .gitignore
│ ├── dub.json
│ └── source
│ │ └── app.d
├── http-client
│ ├── curl-ca-bundle.crt
│ ├── dub.json
│ └── source
│ │ └── app.d
├── mvvm-dlangui
│ ├── dub.json
│ └── source
│ │ ├── app.d
│ │ └── mvvm
│ │ ├── common.d
│ │ ├── models
│ │ └── simple.d
│ │ └── views
│ │ └── simple.d
├── mvvm-gtk-d
│ ├── .gitignore
│ ├── dub.json
│ └── source
│ │ ├── app.d
│ │ └── mvvm
│ │ ├── model.d
│ │ ├── util.d
│ │ └── view.d
├── overview
│ ├── dub.json
│ └── source
│ │ └── app.d
├── rx-dlangui
│ ├── dub.json
│ └── source
│ │ ├── app.d
│ │ ├── event.d
│ │ ├── model.d
│ │ └── win_app.def
├── rx-dnd-gtkd
│ ├── dub.sdl
│ └── source
│ │ └── app.d
├── rx-fswatch
│ ├── data
│ │ └── data.txt
│ ├── dub.json
│ ├── dub.selections.json
│ └── source
│ │ └── app.d
├── rx-gtk-d
│ ├── dub.json
│ └── source
│ │ └── app.d
└── scheduler-dlangui
│ ├── dub.json
│ └── source
│ ├── app.d
│ ├── utils.d
│ └── win_app.def
└── source
└── rx
├── algorithm
├── all.d
├── any.d
├── buffer.d
├── combineLatest.d
├── debounce.d
├── filter.d
├── fold.d
├── groupby.d
├── map.d
├── merge.d
├── package.d
├── scan.d
├── tee.d
└── uniq.d
├── disposable.d
├── observable.d
├── observer.d
├── package.d
├── range
├── drop.d
├── package.d
├── take.d
├── takeLast.d
├── takeUntil.d
└── zip.d
├── scheduler.d
├── subject.d
└── util.d
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 |
7 | # Standard to msysgit
8 | *.doc diff=astextplain
9 | *.DOC diff=astextplain
10 | *.docx diff=astextplain
11 | *.DOCX diff=astextplain
12 | *.dot diff=astextplain
13 | *.DOT diff=astextplain
14 | *.pdf diff=astextplain
15 | *.PDF diff=astextplain
16 | *.rtf diff=astextplain
17 | *.RTF diff=astextplain
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Windows image file caches
2 | Thumbs.db
3 | ehthumbs.db
4 |
5 | # Folder config file
6 | Desktop.ini
7 |
8 | # Recycle Bin used on file shares
9 | $RECYCLE.BIN/
10 |
11 | # Windows Installer files
12 | *.cab
13 | *.msi
14 | *.msm
15 | *.msp
16 |
17 | # Windows shortcuts
18 | *.lnk
19 |
20 | # =========================
21 | # Operating System Files
22 | # =========================
23 |
24 | # OSX
25 | # =========================
26 |
27 | .DS_Store
28 | .AppleDouble
29 | .LSOverride
30 |
31 | # Thumbnails
32 | ._*
33 |
34 | # Files that might appear on external disk
35 | .Spotlight-V100
36 | .Trashes
37 |
38 | # Directories potentially created on remote AFP share
39 | .AppleDB
40 | .AppleDesktop
41 | Network Trash Folder
42 | Temporary Items
43 | .apdisk
44 |
45 | # =========================
46 | # Dlang / Dub
47 | # =========================
48 | .dub
49 | *.obj
50 | *.lib
51 | *.exe
52 | *.pdb
53 | *.lst
54 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: d
2 |
3 | os:
4 | - linux
5 | - osx
6 |
7 | d:
8 | # support 3 versions
9 | - dmd
10 | - dmd-2.100.2
11 | - dmd-2.099.1
12 | - dmd-2.098.1
13 | - ldc
14 | - ldc-1.30.0
15 | - ldc-1.29.0
16 | - ldc-1.28.0
17 |
18 | script:
19 | - dub test -b unittest-cov
20 |
21 | after_success:
22 | - bash <(curl -s https://codecov.io/bash)
23 |
24 | test:
25 | dub test
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | Contributing
2 | ============
3 |
4 | Thank you for your interest!
5 | Issue and pull request are welcome!
6 |
7 |
8 | Development and Testing
9 | -----------------------
10 | We are weolcoming tha refactoring and implements operators.
11 |
12 | `rx` provides attractive code to users, like the general `std.range` and `std.algorithm`. But, its source code is unfortunately complicated.
13 |
14 | In particular, it is important a variety operators combination tests, and multithreading tests.
15 |
16 | ### Things you will need
17 |
18 | * Linux, Mac OS X, or Windows
19 | * git (used for source version control).
20 | * Some D Compiler. dmd and ldc.
21 | * Latest dub (used for build and testing).
22 | * An IDE. We recommend [Visual Studio Code](https://code.visualstudio.com/download) with [code-d](https://marketplace.visualstudio.com/items?itemName=webfreak.code-d).
23 | * Use dfmt (with default settings) for code formatting.
24 |
25 | ### Patterns
26 | Taking `map` as an example, the operator consists of the following three elements.
27 |
28 | - struct `MapObserver`
29 | - struct `MapObservable`
30 | - template function `map`
31 |
32 | #### MapObserver
33 | Observer's role is to provide concrete algorithms in the constructed pipeline.
34 |
35 | `MapObserver` has the function of passing processed values to Observer as source.
36 |
37 | #### MapObservable
38 | Observable as an operator has Observable as a source and has the role of processing a given Observer and constructing a pipeline.
39 |
40 | `MapObservable` has the function of wrapping the passed Observer in `MapObserver` and subscribing to Observable as source.
41 |
42 | Also, since Observable returns `Disposable`, it relays it.
43 |
44 | #### map
45 | It is utility function for build `MapObservable`.
46 |
47 |
48 | ### Naming priority
49 | Unified naming conventions is important. It is now as follows.
50 |
51 | 1. Look for similar operators from `std.algorithm`.
52 | 2. If there are no similar operators, follow [Reactive X](http://reactivex.io/documentation/operators.html).
53 |
54 |
55 | Documentation
56 | -------------
57 | We are welcoming the tutorial documentation.
58 |
59 | For users, the goal is to think about the composition of the tutorial so that you can see how to use it, and to add practical examples.
60 |
61 | For developers, We think that the following things are necessary.
62 |
63 | - Manage the tutorial as part of the source.
64 | - Since the contribution log remains, it is easy to understand later.
65 | - Not separate it into another repository to avoid version inconsistency.
66 | - Keep docs as a simple API reference.
67 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/benchmarks/subject-put/.gitignore:
--------------------------------------------------------------------------------
1 | .dub
2 | docs.json
3 | __dummy.html
4 | docs/
5 | /subscribers
6 | subscribers.so
7 | subscribers.dylib
8 | subscribers.dll
9 | subscribers.a
10 | subscribers.lib
11 | subscribers-test-*
12 | *.exe
13 | *.o
14 | *.obj
15 | *.lst
16 |
--------------------------------------------------------------------------------
/benchmarks/subject-put/dub.json:
--------------------------------------------------------------------------------
1 | {
2 | "authors": [
3 | "lempiji"
4 | ],
5 | "description": "Benchmark for many observers.",
6 | "license": "proprietary",
7 | "name": "subject-put",
8 | "dependencies": {
9 | "rx": { "path": "../../" }
10 | }
11 | }
--------------------------------------------------------------------------------
/benchmarks/subject-put/source/app.d:
--------------------------------------------------------------------------------
1 | /+
2 | Benchmark for many observers.
3 |
4 | [test_rx]
5 | SubjectObject holds the subscribed Observer as an array.
6 | It requires processing time proportional to the number of Observers for one put.
7 |
8 | [test_rx_dispatch]
9 | When it is intended to classify by message type, it is efficient to manage SubjectObject by type using associative arrays.
10 | This idea is "divide and conquer".
11 | +/
12 | import std.stdio;
13 | import std.algorithm : fold;
14 | import std.conv;
15 | import std.meta;
16 |
17 | import rx;
18 |
19 | import core.sys.windows.windows;
20 |
21 | alias message_t = typeof(MSG.init.message);
22 | enum N = 500;
23 | enum M = 100;
24 |
25 | void main()
26 | {
27 | import std.datetime;
28 |
29 | auto data = makeTestData();
30 |
31 | auto t1 = Clock.currTime;
32 | auto r1 = test_rx(data);
33 | auto t2 = Clock.currTime;
34 | auto r2 = test_rx_dispatch(data);
35 | auto t3 = Clock.currTime;
36 |
37 | writeln("N : ", N);
38 | writeln("M : ", M);
39 | writeln("test_rx : ", (t2 - t1).total!"msecs");
40 | writeln("test_rx_dispatch : ", (t3 - t2).total!"msecs");
41 |
42 | writeln("task1 : ", r1.values.fold!"a+b"(0UL) == N * M ? "success" : "failure");
43 | writeln("task2 : ", r2.values.fold!"a+b"(0UL) == N * M ? "success" : "failure");
44 | }
45 |
46 | MSG[] makeTestData()
47 | {
48 | import std.array : appender;
49 | import std.random : uniform;
50 |
51 | auto buf = appender!(MSG[]);
52 | MSG msg;
53 | foreach (_; 0 .. N * M)
54 | {
55 | msg.message = uniform(cast(message_t) 0, cast(message_t) N);
56 | buf.put(msg);
57 | }
58 | return buf.data;
59 | }
60 |
61 | size_t[message_t] test_rx(MSG[] messages)
62 | {
63 | size_t[message_t] counts;
64 |
65 | auto source = new SubjectObject!MSG;
66 |
67 | static foreach (i; 0 .. N)
68 | {
69 | source.filter!(a => a.message == i).doSubscribe!((MSG msg) { counts[msg.message]++; });
70 | }
71 |
72 | foreach (ref msg; messages)
73 | {
74 | source.put(msg);
75 | }
76 |
77 | return counts;
78 | }
79 |
80 | size_t[message_t] test_rx_dispatch(MSG[] messages)
81 | {
82 | size_t[message_t] counts;
83 | SubjectObject!(MSG)[message_t] sources;
84 |
85 | foreach (message_t i; 0 .. N)
86 | {
87 | sources[i] = new SubjectObject!MSG;
88 | sources[i].doSubscribe!((msg) { counts[msg.message]++; });
89 | }
90 |
91 | auto source = new SubjectObject!MSG;
92 | source.doSubscribe!((msg) { sources[msg.message].put(msg); });
93 |
94 | foreach (ref msg; messages)
95 | {
96 | source.put(msg);
97 | }
98 |
99 | return counts;
100 | }
101 |
--------------------------------------------------------------------------------
/deps.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lempiji/rx/d152c7290737c6f07bf0f7b3c24999a1bc0ce751/deps.png
--------------------------------------------------------------------------------
/docs/articles/Practice.ja.md:
--------------------------------------------------------------------------------
1 | # 実践編
2 |
3 | > Note: 文書中の図を正しく表示するためには**PlantUML**が必要です。
4 |
5 | ## GUIアプリケーションへの組み込み
6 | ### 実行スレッドとSchedulerの関係
7 | GUIアプリケーションを作るためのツールキットの多くは、「UIに対する操作」をいわゆる「UIスレッド」で実行しなければならない、という制約があります。
8 |
9 | これはイベントループの操作が公開されたフレームワークでよく見られる制約ですが、たとえば`WinForms`や`WPF`、D言語向けのライブラリでは`dlang-ui`などが該当する非常に一般的な制約です。
10 |
11 | これを解決するためには、「処理がどのスレッドで実行されるか」という点を注意深く確認しながらコーディングする必要があり、非常に手間がかかります。
12 |
13 | 一方、rxにはこれを解決するための`Scheduler`というコンセプトがあります。
14 |
15 | この`Scheduler`を正しく使えば、`subscribe`や`put`/`completed`/`failure`が実行されるスレッドを容易に切り替えることができます。
16 |
17 |
18 | ### Schedulerの目的
19 | GUIアプリケーションにおける`Scheduler`の目的は、多くの場合「重い処理をUIスレッド外へ逃がす」「UIスレッドへ処理をディスパッチする」の2つです。
20 |
21 | 前者は、`subscribeOn`や`observeOn`といったオペレーターに対し、`TaskPoolScheduler`や`ThreadScheduler`を指定することで別スレッドで実行させることができます。これらは組み込みの機能だけで実現できるため、覚えてしまえば特に難しい点はありません。
22 |
23 | 後者は、ツールキット毎に専用の`Scheduler`を作ることで対応する必要があります。このためには、「ツールキットのイベントループを操作する方法」と「`Scheduler`が満たすべき要件」の両方を理解する必要があります。
24 |
25 | > Note: 後者の役割を持った`Scheduler`は、多くの場合`Dispatcher`と呼ばれます。
26 |
27 | ### Dispatcherの作成例(dlang-ui)
28 | Example(scheduler-dlangui)にて、`dlang-ui`向けの`Dispatcher`クラスを公開しています。
29 |
30 | このクラスは、`dlang-ui`が公開している`Timer`クラスを使い、`put`で実行する処理をイベントループにディスパッチします。
31 | これによって、`subscribe`した処理が常にUIスレッドで実行されるようになります。
32 |
33 | ### コード例
34 | 重い処理を「UIスレッドで行う場合」と「ワーカースレッドへ逃がす場合」について、それぞれ疑似コードを示します。
35 |
36 | 適切な`Dispatcher`クラスが定義されているとして、ブロッキングバージョンのロジックに`observeOn`をいくつか挟むだけで実行スレッドを切り替えることができることがわかります。
37 |
38 | ```d
39 | auto sub = SubjectObject!int;
40 |
41 | int heavyFunc(int n)
42 | {
43 | // 重い処理
44 | return result;
45 | }
46 |
47 | auto blocking = sub
48 | .map!(&heavyFunc)
49 | .doSubscribe!(n => label.text = to!string(n));
50 |
51 | auto nonBlocking = sub
52 | .observeOn(new ThreadScheduler)
53 | .map!(&heavyFunc)
54 | .observeOn(new MyDispatcher)
55 | .doSubscribe!(n => label.text = to!string(n));
56 | ```
57 |
58 | これをシーケンス図で比較すると以下のようなイメージになります。
59 |
60 | ```plantuml
61 | @startuml
62 | title blocking
63 |
64 | participant UI
65 |
66 | -> UI : Event
67 | activate UI
68 |
69 | UI -> UI : heavyFunc
70 |
71 |
72 | <- UI
73 | deactivate UI
74 |
75 | @enduml
76 | ```
77 |
78 | ```plantuml
79 | @startuml
80 | title non-blocking
81 |
82 | participant UI
83 | participant WorkerThread
84 |
85 | -> UI : Event
86 | activate UI
87 | UI ->> WorkerThread : observeOn
88 | activate WorkerThread
89 |
90 | <- UI
91 | deactivate UI
92 |
93 | WorkerThread -> WorkerThread : heavyFunc
94 |
95 | UI <<- WorkerThread : observeOn
96 | deactivate WorkerThread
97 | activate UI
98 |
99 | <- UI
100 | deactivate UI
101 |
102 | @enduml
103 | ```
104 |
105 |
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | index (index)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.algorithm.all.all.html:
--------------------------------------------------------------------------------
1 | Continue to overload
--------------------------------------------------------------------------------
/docs/rx.algorithm.any.any.html:
--------------------------------------------------------------------------------
1 | Continue to overload
--------------------------------------------------------------------------------
/docs/rx.algorithm.debounce.debounce.html:
--------------------------------------------------------------------------------
1 | Continue to overload
--------------------------------------------------------------------------------
/docs/rx.algorithm.groupby.GroupedObservable.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | GroupedObservable (rx.algorithm.groupby.GroupedObservable)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
39 |
GroupedObservable
interface GroupedObservable : Observable!E(
) {}
40 |
rxalgorithmgroupby
41 |
interfacestemplates
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.algorithm.merge.merge.html:
--------------------------------------------------------------------------------
1 | Continue to overload
--------------------------------------------------------------------------------
/docs/rx.disposable.AnonymousDisposable.dispose.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | AnonymousDisposable.dispose (rx.disposable.AnonymousDisposable.dispose)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
39 |
AnonymousDisposable.dispose
class AnonymousDisposable
40 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.disposable.AnonymousDisposable.this.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | AnonymousDisposable.this (rx.disposable.AnonymousDisposable.this)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
39 |
AnonymousDisposable.this
class AnonymousDisposable
40 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.disposable.Cancelable.isDisposed.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | Cancelable.isDisposed (rx.disposable.Cancelable.isDisposed)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
39 |
Cancelable.isDisposed
40 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.disposable.CancelableObject.isDisposed.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | CancelableObject.isDisposed (rx.disposable.CancelableObject.isDisposed)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
39 |
CancelableObject.isDisposed
class CancelableObject(T)
40 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.disposable.CancelableObject.this.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | CancelableObject.this (rx.disposable.CancelableObject.this)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
39 |
CancelableObject.this
class CancelableObject(T)
40 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.disposable.CancellationToken.cancel.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | CancellationToken.cancel (rx.disposable.CancellationToken.cancel)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
39 |
CancellationToken.cancel
40 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.disposable.CancellationToken.dispose.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | CancellationToken.dispose (rx.disposable.CancellationToken.dispose)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
39 |
CancellationToken.dispose
40 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.disposable.CancellationToken.isCanceled.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | CancellationToken.isCanceled (rx.disposable.CancellationToken.isCanceled)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
39 |
CancellationToken.isCanceled
40 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.disposable.CancellationToken.isDisposed.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | CancellationToken.isDisposed (rx.disposable.CancellationToken.isDisposed)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
39 |
CancellationToken.isDisposed
40 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.disposable.CompositeDisposable.dispose.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | CompositeDisposable.dispose (rx.disposable.CompositeDisposable.dispose)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
39 |
CompositeDisposable.dispose
class CompositeDisposable
40 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.disposable.Disposable.dispose.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | Disposable.dispose (rx.disposable.Disposable.dispose)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.disposable.DisposableObject.dispose.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | DisposableObject.dispose (rx.disposable.DisposableObject.dispose)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
39 |
DisposableObject.dispose
class DisposableObject(T)
40 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.disposable.DisposableObject.this.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | DisposableObject.this (rx.disposable.DisposableObject.this)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
39 |
DisposableObject.this
class DisposableObject(T)
40 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.disposable.NopDisposable.instance.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | NopDisposable.instance (rx.disposable.NopDisposable.instance)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
39 |
NopDisposable.instance
40 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.disposable.RefCountDisposable.dispose.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | RefCountDisposable.dispose (rx.disposable.RefCountDisposable.dispose)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
39 |
RefCountDisposable.dispose
40 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.disposable.RefCountDisposable.getDisposable.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | RefCountDisposable.getDisposable (rx.disposable.RefCountDisposable.getDisposable)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
39 |
RefCountDisposable.getDisposable
40 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.disposable.SerialDisposable.disposable.html:
--------------------------------------------------------------------------------
1 | Continue to overload
--------------------------------------------------------------------------------
/docs/rx.disposable.SerialDisposable.dispose.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | SerialDisposable.dispose (rx.disposable.SerialDisposable.dispose)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
39 |
SerialDisposable.dispose
40 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.disposable.SerialDisposable.isDisposed.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | SerialDisposable.isDisposed (rx.disposable.SerialDisposable.isDisposed)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
39 |
SerialDisposable.isDisposed
40 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.disposable.SignalDisposable.dispose.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | SignalDisposable.dispose (rx.disposable.SignalDisposable.dispose)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
39 |
SignalDisposable.dispose
40 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.disposable.SignalDisposable.signal.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | SignalDisposable.signal (rx.disposable.SignalDisposable.signal)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
39 |
SignalDisposable.signal
class SignalDisposable
EventSignal
signal
@
property
40 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.disposable.SingleAssignmentDisposable.dispose.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | SingleAssignmentDisposable.dispose (rx.disposable.SingleAssignmentDisposable.dispose)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
39 |
SingleAssignmentDisposable.dispose
class SingleAssignmentDisposable
40 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.disposable.SingleAssignmentDisposable.isDisposed.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | SingleAssignmentDisposable.isDisposed (rx.disposable.SingleAssignmentDisposable.isDisposed)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
39 |
SingleAssignmentDisposable.isDisposed
class SingleAssignmentDisposable
40 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.disposable.withDisposed.html:
--------------------------------------------------------------------------------
1 | Continue to overload
--------------------------------------------------------------------------------
/docs/rx.observable.doSubscribe.html:
--------------------------------------------------------------------------------
1 | Continue to overload
--------------------------------------------------------------------------------
/docs/rx.observable.isObservable.html:
--------------------------------------------------------------------------------
1 | Continue to overload
--------------------------------------------------------------------------------
/docs/rx.observer.NopObserver.instance.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | NopObserver.instance (rx.observer.NopObserver.instance)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
39 |
NopObserver.instance
40 |
rxobserverNopObserver
41 |
static functions
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.observer.Observer.completed.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | Observer.completed (rx.observer.Observer.completed)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.observer.Observer.failure.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | Observer.failure (rx.observer.Observer.failure)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.observer.ObserverObject.completed.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | ObserverObject.completed (rx.observer.ObserverObject.completed)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
39 |
ObserverObject.completed
class ObserverObject(R, E...)
40 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.observer.ObserverObject.failure.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | ObserverObject.failure (rx.observer.ObserverObject.failure)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
39 |
ObserverObject.failure
class ObserverObject(R, E...)
40 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.observer.makeObserver.html:
--------------------------------------------------------------------------------
1 | Continue to overload
--------------------------------------------------------------------------------
/docs/rx.range.drop.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | rx.range.drop (rx.range.drop)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
39 |
rx.range.drop
- drop
auto drop(auto ref TObservable observable, size_t n)
Creates the observable that results from discarding the first n elements from the given source.
41 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/docs/rx.range.take.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | rx.range.take (rx.range.take)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
39 |
rx.range.take
- take
auto take(auto ref TObservable observable, size_t n)
Creates a sub-observable consisting of only up to the first n elements of the given source.
41 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/docs/rx.range.takeLast.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | rx.range.takeLast (rx.range.takeLast)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
39 |
rx.range.takeLast
- takeLast
auto takeLast(auto ref TObservable observable)
Creates a observable that take only a last element of the given source.
41 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/docs/rx.range.takeUntil.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | rx.range.takeUntil (rx.range.takeUntil)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
39 |
rx.range.takeUntil
- takeUntil
auto takeUntil(auto ref TObservable1 source, auto ref TObservable2 stopper)
41 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/docs/rx.range.zip.GetElementsTuple.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | GetElementsTuple (rx.range.zip.GetElementsTuple)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
39 |
GetElementsTuple
template GetElementsTuple (
) {}
40 |
rxrangezip
41 |
aliasesclassesstructstemplates
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.range.zip.GetZipStoreTypeImpl.GetZipStoreTypeImpl.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | GetZipStoreTypeImpl.GetZipStoreTypeImpl (rx.range.zip.GetZipStoreTypeImpl.GetZipStoreTypeImpl)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
39 |
GetZipStoreTypeImpl.GetZipStoreTypeImpl
template GetZipStoreTypeImpl(TObserver)
alias GetZipStoreTypeImpl(E) =
ZipStore!(
E,
hasCompleted!
TObserver)
40 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.range.zip.ZipNObservable.ElementType.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | ZipNObservable.ElementType (rx.range.zip.ZipNObservable.ElementType)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
39 |
ZipNObservable.ElementType
class ZipNObservable(alias selector, TObservables...)
alias ElementType =
typeof( ())
40 |
rxrangezipZipNObservable
41 |
aliasesconstructorsfunctions
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.scheduler.HistoricalScheduler.this.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | HistoricalScheduler.this (rx.scheduler.HistoricalScheduler.this)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
39 |
HistoricalScheduler.this
class HistoricalScheduler(T)
40 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.scheduler.LocalScheduler.start.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | LocalScheduler.start (rx.scheduler.LocalScheduler.start)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
39 |
LocalScheduler.start
40 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.scheduler.MostDerivedScheduler.MostDerivedScheduler.html:
--------------------------------------------------------------------------------
1 | Continue to overload
--------------------------------------------------------------------------------
/docs/rx.scheduler.ObserveOnObserver.completed.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | ObserveOnObserver.completed (rx.scheduler.ObserveOnObserver.completed)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
39 |
ObserveOnObserver.completed
struct ObserveOnObserver(TObserver, TScheduler, E)
40 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.scheduler.ObserveOnObserver.this.html:
--------------------------------------------------------------------------------
1 | Continue to overload
--------------------------------------------------------------------------------
/docs/rx.scheduler.Scheduler.start.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | Scheduler.start (rx.scheduler.Scheduler.start)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.scheduler.SchedulerObject.this.html:
--------------------------------------------------------------------------------
1 | Continue to overload
--------------------------------------------------------------------------------
/docs/rx.scheduler.TaskPoolScheduler.this.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | TaskPoolScheduler.this (rx.scheduler.TaskPoolScheduler.this)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
39 |
TaskPoolScheduler.this
40 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.scheduler.ThreadScheduler.start.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | ThreadScheduler.start (rx.scheduler.ThreadScheduler.start)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
39 |
ThreadScheduler.start
40 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.scheduler.currentScheduler.html:
--------------------------------------------------------------------------------
1 | Continue to overload
--------------------------------------------------------------------------------
/docs/rx.subject.AsyncSubject.completed.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | AsyncSubject.completed (rx.subject.AsyncSubject.completed)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
39 |
AsyncSubject.completed
40 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.subject.AsyncSubject.subscribe.html:
--------------------------------------------------------------------------------
1 | Continue to overload
--------------------------------------------------------------------------------
/docs/rx.subject.BehaviorSubject.completed.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | BehaviorSubject.completed (rx.subject.BehaviorSubject.completed)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
39 |
BehaviorSubject.completed
40 |
rxsubjectBehaviorSubject
41 |
constructorsfunctions
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.subject.BehaviorSubject.subscribe.html:
--------------------------------------------------------------------------------
1 | Continue to overload
--------------------------------------------------------------------------------
/docs/rx.subject.BehaviorSubject.this.html:
--------------------------------------------------------------------------------
1 | Continue to overload
--------------------------------------------------------------------------------
/docs/rx.subject.BehaviorSubject.value.html:
--------------------------------------------------------------------------------
1 | Continue to overload
--------------------------------------------------------------------------------
/docs/rx.subject.ReplaySubject.completed.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | ReplaySubject.completed (rx.subject.ReplaySubject.completed)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
39 |
ReplaySubject.completed
40 |
rxsubjectReplaySubject
41 |
constructorsfunctions
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.subject.ReplaySubject.subscribe.html:
--------------------------------------------------------------------------------
1 | Continue to overload
--------------------------------------------------------------------------------
/docs/rx.subject.Subject.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | Subject (rx.subject.Subject)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
39 |
Subject
interface Subject : Observer!E, Observable!E(
)
40 |
rxsubject
41 |
classesfunctionsinterfaces
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.subject.SubjectObject.completed.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | SubjectObject.completed (rx.subject.SubjectObject.completed)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
39 |
SubjectObject.completed
40 |
rxsubjectSubjectObject
41 |
constructorsfunctions
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.subject.SubjectObject.subscribe.html:
--------------------------------------------------------------------------------
1 | Continue to overload
--------------------------------------------------------------------------------
/docs/rx.subject.SubjectObject.this.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | SubjectObject.this (rx.subject.SubjectObject.this)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
40 |
rxsubjectSubjectObject
41 |
constructorsfunctions
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.util.AtomicCounter.isZero.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | AtomicCounter.isZero (rx.util.AtomicCounter.isZero)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
39 |
AtomicCounter.isZero
40 |
rxutilAtomicCounter
41 |
constructorsfunctions
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.util.AtomicCounter.tryDecrement.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | AtomicCounter.tryDecrement (rx.util.AtomicCounter.tryDecrement)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
39 |
AtomicCounter.tryDecrement
40 |
rxutilAtomicCounter
41 |
constructorsfunctions
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.util.AtomicCounter.trySetZero.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | AtomicCounter.trySetZero (rx.util.AtomicCounter.trySetZero)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
39 |
AtomicCounter.trySetZero
40 |
rxutilAtomicCounter
41 |
constructorsfunctions
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.util.AtomicCounter.tryUpdateCount.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | AtomicCounter.tryUpdateCount (rx.util.AtomicCounter.tryUpdateCount)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
39 |
AtomicCounter.tryUpdateCount
class AtomicCounter
bool
tryUpdateCount
@
trusted
40 |
rxutilAtomicCounter
41 |
constructorsfunctions
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.util.EventSignal.setSignal.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | EventSignal.setSignal (rx.util.EventSignal.setSignal)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
39 |
EventSignal.setSignal
40 |
rxutilEventSignal
41 |
constructorsfunctions
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.util.EventSignal.signal.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | EventSignal.signal (rx.util.EventSignal.signal)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
40 |
rxutilEventSignal
41 |
constructorsfunctions
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.util.EventSignal.this.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | EventSignal.this (rx.util.EventSignal.this)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
40 |
rxutilEventSignal
41 |
constructorsfunctions
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.util.EventSignal.wait.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | EventSignal.wait (rx.util.EventSignal.wait)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
40 |
rxutilEventSignal
41 |
constructorsfunctions
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.util.TicketBase.isStamped.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | TicketBase.isStamped (rx.util.TicketBase.isStamped)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
38 |
39 |
TicketBase.isStamped
40 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.util.TicketBase.stamp.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 | TicketBase.stamp (rx.util.TicketBase.stamp)
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
37 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/docs/rx.util.assumeThreadLocal.html:
--------------------------------------------------------------------------------
1 | Continue to overload
--------------------------------------------------------------------------------
/docs/search-docs.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
19 |
20 |
21 |
26 |
27 |
--------------------------------------------------------------------------------
/dub.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "rx",
3 | "description": "Reactive Extensions for D Programming Language.",
4 | "copyright": "Copyright © 2015, lempiji",
5 | "license": "MIT",
6 | "homepage": "https://github.com/lempiji/rx",
7 | "authors": [
8 | "lempiji"
9 | ],
10 | "sourcePaths": [
11 | "source"
12 | ],
13 | "configurations": [
14 | {
15 | "name": "default",
16 | "targetType": "library"
17 | },
18 | {
19 | "name": "unittest",
20 | "dependencies": {
21 | "silly": "~>1.1.1"
22 | }
23 | },
24 | {
25 | "name": "diff",
26 | "postGenerateCommands": [
27 | "dub build -c makedeps -f",
28 | "dub fetch ddeps",
29 | "dub run ddeps -- --focus=rx --output=deps.dot",
30 | "dot -Tsvg -odeps.svg deps.dot",
31 | "dot -Tpng -odeps.png deps.dot"
32 | ]
33 | },
34 | {
35 | "name": "diff-update",
36 | "postGenerateCommands": [
37 | "dub fetch ddeps",
38 | "dub run ddeps -- --update"
39 | ]
40 | },
41 | {
42 | "name": "makedeps",
43 | "dflags": ["-deps=deps.txt"]
44 | }
45 | ]
46 | }
--------------------------------------------------------------------------------
/dub.selections.json:
--------------------------------------------------------------------------------
1 | {
2 | "fileVersion": 1,
3 | "versions": {
4 | "silly": "1.1.1"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/examples/concurrency/.gitignore:
--------------------------------------------------------------------------------
1 | .dub
2 | docs.json
3 | __dummy.html
4 | docs/
5 | concurrency.so
6 | concurrency.dylib
7 | concurrency.dll
8 | concurrency.a
9 | concurrency.lib
10 | concurrency-test-*
11 | *.exe
12 | *.o
13 | *.obj
14 | *.lst
15 |
--------------------------------------------------------------------------------
/examples/concurrency/dub.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "concurrency",
3 | "authors": [
4 | "lempiji"
5 | ],
6 | "dependencies": {
7 | "rx": { "path": "../../" }
8 | }
9 | }
--------------------------------------------------------------------------------
/examples/concurrency/source/app.d:
--------------------------------------------------------------------------------
1 | import rx;
2 |
3 | import core.time;
4 | import core.thread;
5 |
6 | import std.concurrency;
7 | import std.range : put;
8 | import std.stdio;
9 |
10 | void main()
11 | {
12 | auto timer = new ThreadTimer(1.seconds);
13 | auto counter = timer.scan!"a + 1"(0); // count up per 1sec
14 |
15 | auto receiver = counter.getReceiver();
16 | scope (exit)
17 | receiver.dispose();
18 |
19 | timer.start();
20 | scope (exit)
21 | timer.stop();
22 |
23 | auto n0 = receiver.receive();
24 | writeln(n0);
25 | auto n1 = receiver.receive();
26 | writeln(n1);
27 | auto n2 = receiver.receive();
28 | writeln(n2);
29 | }
30 |
31 | auto getReceiver(TObservable)(auto ref TObservable observable)
32 | {
33 | auto tid = thisTid;
34 | auto disposable = observable.doSubscribe!((TObservable.ElementType elem) {
35 | send(tid, elem);
36 | });
37 |
38 | static struct Receiver
39 | {
40 | typeof(disposable) _disposable;
41 |
42 | TObservable.ElementType receive()
43 | {
44 | return receiveOnly!(TObservable.ElementType);
45 | }
46 |
47 | void dispose()
48 | {
49 | _disposable.dispose();
50 | }
51 | }
52 |
53 | return Receiver(disposable);
54 | }
55 |
56 | class ThreadTimer : SubjectObject!bool
57 | {
58 | Thread _thread;
59 | shared(bool) _shutdown;
60 | const(Duration) _interval;
61 |
62 | this(Duration interval)
63 | {
64 | _interval = interval;
65 | _thread = new Thread(&this.run);
66 | }
67 |
68 | void start()
69 | {
70 | _thread.start();
71 | }
72 |
73 | void stop()
74 | in(_thread !is null)
75 | {
76 | _shutdown = true;
77 | }
78 |
79 | private void run()
80 | {
81 | if (!_shutdown)
82 | this.put(true);
83 | while (!_shutdown)
84 | {
85 | Thread.sleep(_interval);
86 | if (!_shutdown)
87 | this.put(true);
88 | }
89 | this.completed();
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/examples/fizzbuzz/.gitignore:
--------------------------------------------------------------------------------
1 | .dub
2 | docs.json
3 | __dummy.html
4 | *.o
5 | *.obj
6 |
--------------------------------------------------------------------------------
/examples/fizzbuzz/dub.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "fizzbuzz",
3 | "authors": [
4 | "lempiji"
5 | ],
6 | "description": "A example for rx.",
7 | "dependencies": {
8 | "rx": {
9 | "path": "../../"
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/examples/fizzbuzz/source/app.d:
--------------------------------------------------------------------------------
1 | import std.conv;
2 | import std.range;
3 | import std.stdio;
4 | import rx;
5 |
6 | void main()
7 | {
8 | // 1) make source stream for 0 to 99
9 | auto sub = new SubjectObject!int;
10 |
11 | // 2) source map to Fizz or Buzz or numbers
12 | auto fizz = sub.filter!"a % 3 == 0"().map!(_ => "Fizz");
13 | auto buzz = sub.filter!"a % 5 == 0"().map!(_ => "Buzz");
14 | auto num = sub.filter!(a => a % 3 != 0 && a % 5 != 0).map!(to!string);
15 | auto tokens = fizz.merge(buzz).merge(num);
16 |
17 | // 3) source map to newline for delimiters
18 | auto newlines = sub.map!(_ => "\n");
19 |
20 | // 4) merge tokens and newline
21 | // e.g.
22 | // 1 -> ( none , none , "1", "\n") -> write("1"); write("\n");
23 | // 3 -> ("Fizz", none , none, "\n") -> write("Fizz"); write("\n");
24 | // 5 -> ( none , "Buzz", none, "\n") -> write("Buzz"); write("\n");
25 | // 15 -> ("Fizz", "Buzz", none, "\n") -> write("Fizz"); write("Buzz"); write("\n");
26 | merge(tokens, newlines).doSubscribe!(token => write(token));
27 |
28 | // 5) run with numbers
29 | .put(sub, iota(100));
30 | }
31 |
--------------------------------------------------------------------------------
/examples/http-client/dub.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "http-client",
3 | "authors": [
4 | "lempiji"
5 | ],
6 | "description": "The example for an async http utilities",
7 | "copyright": "Copyright © 2017, lempiji",
8 | "license": "MIT",
9 | "dependencies": {
10 | "rx": {
11 | "path": "../../"
12 | }
13 | },
14 | "libs": [
15 | "curl"
16 | ]
17 | }
--------------------------------------------------------------------------------
/examples/http-client/source/app.d:
--------------------------------------------------------------------------------
1 | import std.algorithm : splitter;
2 | import std.stdio;
3 | import std.range : put, take;
4 | import rx;
5 |
6 | void main()
7 | {
8 | auto signal = new EventSignal;
9 | auto client = getAsync("dlang.org");
10 |
11 | // dfmt off
12 | client.map!(content => content.length)
13 | .doSubscribe((size_t length) {
14 | writeln("Content-Length: ", length);
15 | }, () {
16 | signal.setSignal();
17 | }, (Exception e) {
18 | writeln(e);
19 | signal.setSignal();
20 | });
21 | // dfmt on
22 |
23 | signal.wait();
24 | }
25 |
26 | Observable!(char[]) getAsync(const(char)[] url)
27 | {
28 | auto sub = new AsyncSubject!(char[]);
29 |
30 | import std.net.curl : HTTP, get;
31 | import std.parallelism : task, taskPool;
32 |
33 | taskPool.put(task({
34 | auto http = HTTP(url);
35 | http.caInfo = "./curl-ca-bundle.crt";
36 |
37 | try
38 | {
39 | .put(sub, get(url, http));
40 | sub.completed();
41 | }
42 | catch (Exception e)
43 | {
44 | sub.failure(e);
45 | }
46 | }));
47 |
48 | return sub;
49 | }
50 |
51 | auto getDefer(const(char)[] url)
52 | {
53 | return defer!(char[])((Observer!(char[]) observer) {
54 | import std.net.curl : HTTP, get;
55 |
56 | try
57 | {
58 | auto http = HTTP(url);
59 | http.caInfo = "./curl-ca-bundle.crt";
60 |
61 | .put(observer, get(url, http));
62 | observer.completed();
63 | }
64 | catch (Exception e)
65 | {
66 | observer.failure(e);
67 | }
68 |
69 | return NopDisposable.instance;
70 | }).subscribeOn(new TaskPoolScheduler);
71 | }
72 |
--------------------------------------------------------------------------------
/examples/mvvm-dlangui/dub.json:
--------------------------------------------------------------------------------
1 | {
2 | "authors": [
3 | "lempiji"
4 | ],
5 | "copyright": "Copyright © 2016, lempiji",
6 | "dependencies": {
7 | "dlangui": "~>0.9.188",
8 | "rx": {
9 | "path": "../../"
10 | }
11 | },
12 | "description": "The example for MVVM on Dlang UI",
13 | "license": "MIT",
14 | "name": "mvvm-dlangui"
15 | }
--------------------------------------------------------------------------------
/examples/mvvm-dlangui/source/app.d:
--------------------------------------------------------------------------------
1 | module app;
2 |
3 | import dlangui;
4 | import rx;
5 |
6 | import mvvm.common;
7 | import mvvm.models.simple;
8 | import mvvm.views.simple;
9 |
10 | mixin APP_ENTRY_POINT;
11 |
12 | /// entry point for dlangui based application
13 | extern (C) int UIAppMain(string[] args)
14 | {
15 | auto window = Platform.instance.createWindow("Sample Window", null);
16 |
17 | auto view = createSimpleView();
18 | window.mainWidget = view;
19 | auto viewModel = new SimpleViewModel;
20 |
21 | // bind command and properties
22 | bindText(view.childById!EditLine("txtTitle"), viewModel.title);
23 | bindText(view.childById!TextWidget("lblTitle"), viewModel.title);
24 | bind(view.childById!SwitchButton("switchIsActive"), viewModel.isActive);
25 | bind(view.childById!Button("btnResetTitle"), viewModel.clearTitleCommand);
26 |
27 | // show window
28 | window.show();
29 |
30 | // run message loop
31 | return Platform.instance.enterMessageLoop();
32 | }
33 |
--------------------------------------------------------------------------------
/examples/mvvm-dlangui/source/mvvm/models/simple.d:
--------------------------------------------------------------------------------
1 | module mvvm.models.simple;
2 |
3 | import std.stdio;
4 | import mvvm.common;
5 |
6 | class SimpleViewModel
7 | {
8 | private ReactiveProperty!string _title;
9 | public inout(ReactiveProperty!string) title() inout @property
10 | {
11 | return _title;
12 | }
13 |
14 | private ReactiveProperty!bool _isActive;
15 | public inout(ReactiveProperty!bool) isActive() inout @property
16 | {
17 | return _isActive;
18 | }
19 |
20 | private Command _clearTitleCommand;
21 | public inout(Command) clearTitleCommand() inout @property
22 | {
23 | return _clearTitleCommand;
24 | }
25 |
26 | this()
27 | {
28 | _title = new ReactiveProperty!string("");
29 | _isActive = new ReactiveProperty!bool(false);
30 |
31 | _clearTitleCommand = new DelegateCommand(&clearTitle, isActive);
32 | }
33 |
34 | void clearTitle()
35 | {
36 | if (isActive.value)
37 | title.value = "";
38 | }
39 | }
40 |
41 | unittest
42 | {
43 | auto model = new SimpleViewModel;
44 | assert(model.isActive.value == false);
45 | assert(model.title.value == "");
46 |
47 | model.title.value = "ABC";
48 |
49 | assert(model.title.value == "ABC");
50 | model.clearTitle();
51 | assert(model.title.value == "ABC");
52 |
53 | model.isActive.value = true;
54 | model.clearTitle();
55 | assert(model.title.value == "");
56 | }
57 |
--------------------------------------------------------------------------------
/examples/mvvm-dlangui/source/mvvm/views/simple.d:
--------------------------------------------------------------------------------
1 | module mvvm.views.simple;
2 |
3 | import dlangui;
4 |
5 | Widget createSimpleView()
6 | {
7 | return parseML(q{
8 | VerticalLayout {
9 | EditLine { id: txtTitle; enabled: true }
10 | TextWidget { id: lblTitle }
11 | SwitchButton { id: switchIsActive }
12 | Button { id: btnResetTitle; text: "Reset" }
13 | }
14 | });
15 | }
16 |
--------------------------------------------------------------------------------
/examples/mvvm-gtk-d/.gitignore:
--------------------------------------------------------------------------------
1 | .dub
2 | docs.json
3 | __dummy.html
4 | docs/
5 | /mvvm-gtk-d
6 | mvvm-gtk-d.so
7 | mvvm-gtk-d.dylib
8 | mvvm-gtk-d.dll
9 | mvvm-gtk-d.a
10 | mvvm-gtk-d.lib
11 | mvvm-gtk-d-test-*
12 | *.exe
13 | *.o
14 | *.obj
15 | *.lst
16 |
--------------------------------------------------------------------------------
/examples/mvvm-gtk-d/dub.json:
--------------------------------------------------------------------------------
1 | {
2 | "authors": [
3 | "lempiji"
4 | ],
5 | "dependencies": {
6 | "gtk-d": "~>3.10.0",
7 | "rx": {
8 | "path": "../../"
9 | }
10 | },
11 | "description": "The example for MVVM on Gtk-D",
12 | "license": "MIT",
13 | "name": "mvvm-gtk-d"
14 | }
--------------------------------------------------------------------------------
/examples/mvvm-gtk-d/source/app.d:
--------------------------------------------------------------------------------
1 | module app;
2 |
3 | import gtk.Main;
4 | import gtk.Widget;
5 |
6 | import mvvm.model;
7 | import mvvm.view;
8 |
9 | void main(string[] args)
10 | {
11 | Main.init(args);
12 |
13 | auto viewModel = new AppViewModel;
14 | auto window = new MyAppWindow(viewModel);
15 | window.addOnDestroy((Widget _) { Main.quit(); });
16 |
17 | window.showAll();
18 |
19 | Main.run();
20 | }
21 |
--------------------------------------------------------------------------------
/examples/mvvm-gtk-d/source/mvvm/util.d:
--------------------------------------------------------------------------------
1 | module mvvm.util;
2 |
3 | import std.range : put;
4 |
5 | import gobject.Signals;
6 |
7 | import gtk.Button;
8 | import gtk.Entry;
9 | import gtk.Label;
10 |
11 | import rx;
12 |
13 | Entry toBindedEntry(Subject!string source, CompositeDisposable bag)
14 | {
15 | auto entry = new Entry;
16 | auto handleId = entry.addOnChanged(_ => .put(source, entry.getText()));
17 | bag.insert(new AnonymousDisposable({
18 | Signals.handlerDisconnect(entry, handleId);
19 | }));
20 | bag.insert(source.doSubscribe((string text) { entry.setText(text); }));
21 | return entry;
22 | }
23 |
24 | Label toBindedLabel(TObservable)(auto ref TObservable source, CompositeDisposable bag)
25 | {
26 | import std.conv;
27 |
28 | auto label = new Label("");
29 | bag.insert(source.doSubscribe((TObservable.ElementType obj) {
30 | label.setText(obj.to!string);
31 | }));
32 | return label;
33 | }
34 |
35 | Button makeBindedButton(string text, void delegate() onClick, Observable!bool sensitiveSource, CompositeDisposable disposeBag)
36 | in
37 | {
38 | const hasSensitiveSource = sensitiveSource !is null;
39 | const hasDisposeBag = disposeBag !is null;
40 | if (hasSensitiveSource)
41 | assert(hasDisposeBag);
42 | }
43 | do
44 | {
45 | auto button = new Button(text);
46 | button.addOnClicked((Button _) { onClick(); });
47 | if (sensitiveSource !is null)
48 | {
49 | disposeBag.insert(sensitiveSource.doSubscribe(&button.setSensitive));
50 | }
51 | return button;
52 | }
53 |
54 | Button makeBindedButton(string text, void delegate() onClick, CompositeDisposable disposeBag)
55 | {
56 | return makeBindedButton(text, onClick, null, disposeBag);
57 | }
58 |
--------------------------------------------------------------------------------
/examples/mvvm-gtk-d/source/mvvm/view.d:
--------------------------------------------------------------------------------
1 | module mvvm.view;
2 |
3 | import core.time;
4 |
5 | import gtk.MainWindow;
6 | import gtk.Box;
7 | import gtk.Entry;
8 | import gtk.Label;
9 | import gtk.Button;
10 | import gtk.Widget;
11 |
12 | import rx;
13 |
14 | import mvvm.model;
15 | import mvvm.util;
16 |
17 | class MyAppWindow : MainWindow
18 | {
19 | this(AppViewModel model)
20 | {
21 | super("rx example");
22 | setDefaultSize(640, 480);
23 |
24 | auto disposeBag = new CompositeDisposable;
25 | this.addOnDestroy((Widget _) { disposeBag.dispose(); });
26 |
27 | auto name = model.name.toBindedEntry(disposeBag);
28 | auto age = model.age.toBindedLabel(disposeBag);
29 | auto profile = model.profile.debounce(500.msecs).toBindedLabel(disposeBag);
30 | auto incrementAge = makeBindedButton("+1", &model.incrementAge, disposeBag);
31 | auto decrementAge = makeBindedButton("-1", &model.decrementAge,
32 | model.canDecrementAge, disposeBag);
33 | auto clear = makeBindedButton("Clear", {
34 | model.clear();
35 | profile.setText("");
36 | }, model.canClear, disposeBag);
37 |
38 | auto box = new Box(GtkOrientation.VERTICAL, 5);
39 | box.packStart(makeLine("Name:", name), false, false, 0);
40 | box.packStart(makeLine("Age:", age, decrementAge, incrementAge), false, false, 0);
41 | box.packStart(makeLine("Profile:", profile), false, false, 0);
42 | box.packStart(clear, false, false, 0);
43 | add(box);
44 | }
45 | }
46 |
47 | Box makeLine(string name, Widget[] widgets...)
48 | {
49 | auto box = new Box(GtkOrientation.HORIZONTAL, 5);
50 | box.packStart(new Label(name), false, false, 0);
51 | foreach (widget; widgets)
52 | box.packStart(widget, false, false, 0);
53 | return box;
54 | }
55 |
--------------------------------------------------------------------------------
/examples/overview/dub.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "overview",
3 | "authors": [
4 | "lempiji"
5 | ],
6 | "description": "A example for rx.",
7 | "dependencies": {
8 | "rx": {
9 | "path": "../../"
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/examples/overview/source/app.d:
--------------------------------------------------------------------------------
1 | import rx;
2 | import std.conv : to;
3 | import std.range : iota, put;
4 |
5 | void main()
6 | {
7 | // create own source of int
8 | auto subject = new SubjectObject!int;
9 |
10 | // define result array
11 | string[] result;
12 |
13 | // define pipeline and subscribe
14 | // sequence: source -> filter by even -> map to string -> join to result
15 | auto disposable = subject.filter!(n => n % 2 == 0).map!(o => to!string(o))
16 | .doSubscribe!(text => result ~= text);
17 |
18 | // set unsubscribe on exit
19 | // it is not necessary in this simple example,
20 | // but in many cases you should call dispose to prevent memory leaks.
21 | scope (exit)
22 | disposable.dispose();
23 |
24 | // put values to source.
25 | put(subject, iota(10));
26 |
27 | // result is like this
28 | assert(result == ["0", "2", "4", "6", "8"]);
29 | }
30 |
--------------------------------------------------------------------------------
/examples/rx-dlangui/dub.json:
--------------------------------------------------------------------------------
1 | {
2 | "authors": [
3 | "lempiji"
4 | ],
5 | "copyright": "Copyright © 2016, lempiji",
6 | "dependencies": {
7 | "dlangui": "~>0.9.188",
8 | "rx": {
9 | "path": "../../"
10 | }
11 | },
12 | "description": "The example for rx with Dlang UI.",
13 | "license": "public domain",
14 | "name": "rx-dlangui"
15 | }
--------------------------------------------------------------------------------
/examples/rx-dlangui/source/app.d:
--------------------------------------------------------------------------------
1 | module app;
2 |
3 | import dlangui;
4 | import rx;
5 | import std.conv;
6 |
7 | //main of this sample
8 | import event;
9 | import model;
10 |
11 | mixin APP_ENTRY_POINT;
12 |
13 | /// entry point for dlangui based application
14 | extern (C) int UIAppMain(string[] args)
15 | {
16 | auto window = createAppWindow();
17 | auto appModel = new MyModel;
18 |
19 | auto counter = window.mainWidget.childById!EditLine("counter");
20 |
21 | appModel.counter.doSubscribe((int n) { counter.text = to!dstring(n); });
22 | counter.text = to!dstring(appModel.count);
23 |
24 | Disposable[] events;
25 | events ~= window.mainWidget.childById!Button("btnIncrement")
26 | .click.asObservable().doSubscribe((Widget _) { appModel.increment(); });
27 | events ~= window.mainWidget.childById!Button("btnDecrement")
28 | .click.asObservable().doSubscribe((Widget _) { appModel.decrement(); });
29 |
30 | window.mainWidget.childById!Button("btnDetach").click = (Widget _) {
31 | foreach (e; events)
32 | e.dispose();
33 | return true;
34 | };
35 |
36 | // close window on Close button click
37 | window.mainWidget.childById!Button("btnClose").click = delegate(Widget _) {
38 | window.close();
39 | return true;
40 | };
41 |
42 | // show window
43 | window.show();
44 |
45 | // run message loop
46 | return Platform.instance.enterMessageLoop();
47 | }
48 |
49 | Window createAppWindow()
50 | {
51 | // create window
52 | Log.d("Creating window");
53 | if (!Platform.instance)
54 | {
55 | Log.e("Platform.instance is null!!!");
56 | }
57 |
58 | auto window = Platform.instance.createWindow("DlangUI with Rx", null);
59 | Log.d("Window created");
60 |
61 | // create some widget to show in window
62 | window.mainWidget = parseML(q{
63 | VerticalLayout {
64 | padding: 10
65 | layoutWidth: fill
66 | backgroundColor: "#C0E0E070" // semitransparent yellow background
67 |
68 | // red bold text with size = 150% of base style size and font face Arial
69 | TextWidget { text: "The example for Rx on DlangUI"; textColor: "red"; fontSize: 150%; fontWeight: 800; fontFace: "'Yu Gothic',Arial" }
70 |
71 | // arrange some checkboxes horizontally
72 | HorizontalLayout {
73 | layoutWidth: fill
74 |
75 | TextWidget { text: "Counter" }
76 | EditLine { id: counter; text: "some text"; layoutWidth: fill }
77 |
78 | Button { id: btnIncrement; text: "+1" }
79 | Button { id: btnDecrement; text: "-1" }
80 | }
81 |
82 | Button { id: btnDetach; text: "Detach" }
83 |
84 | Button { id: btnClose; text: "Close" }
85 | }
86 | });
87 |
88 | return window;
89 | }
90 |
--------------------------------------------------------------------------------
/examples/rx-dlangui/source/event.d:
--------------------------------------------------------------------------------
1 | module event;
2 |
3 | import std.traits;
4 | import rx;
5 | import dlangui.core.signals;
6 |
7 | ///Wrap a Signal!T as Observable
8 | auto asObservable(T)(ref T signal) if (is(T == Signal!U, U) && is(U == interface))
9 | {
10 | static if (is(T == Signal!U, U))
11 | {
12 | alias return_t = ReturnType!(__traits(getMember, U, __traits(allMembers, U)[0]));
13 | alias param_t = ParameterTypeTuple!(__traits(getMember, U, __traits(allMembers, U)[0]));
14 | static assert(param_t.length == 1);
15 | }
16 |
17 | static struct LocalObservable
18 | {
19 | alias ElementType = param_t[0];
20 | this(ref T signal)
21 | {
22 | _subscribe = (Observer!ElementType o) {
23 | auto dg = (ElementType w) {
24 | o.put(w);
25 | static if (is(return_t == bool))
26 | {
27 | return true;
28 | }
29 | };
30 |
31 | signal.connect(dg);
32 |
33 | return new AnonymousDisposable({ signal.disconnect(dg); });
34 | };
35 | }
36 |
37 | auto subscribe(U)(U observer)
38 | {
39 | return _subscribe(observerObject!ElementType(observer));
40 | }
41 |
42 | Disposable delegate(Observer!ElementType) _subscribe;
43 | }
44 |
45 | return LocalObservable(signal);
46 | }
47 |
--------------------------------------------------------------------------------
/examples/rx-dlangui/source/model.d:
--------------------------------------------------------------------------------
1 | module model;
2 |
3 | import rx;
4 |
5 | class MyModel
6 | {
7 | public:
8 | this()
9 | {
10 | _count = 0;
11 | _counter = new SubjectObject!int;
12 | }
13 |
14 | public:
15 | int count() @property
16 | {
17 | return _count;
18 | }
19 |
20 | Observable!int counter() @property
21 | {
22 | return _counter;
23 | }
24 |
25 | public:
26 | void increment()
27 | {
28 | _count++;
29 | _counter.put(_count);
30 | }
31 |
32 | void decrement()
33 | {
34 | _count--;
35 | _counter.put(_count);
36 | }
37 |
38 | private:
39 | int _count;
40 | SubjectObject!int _counter;
41 | }
42 |
--------------------------------------------------------------------------------
/examples/rx-dlangui/source/win_app.def:
--------------------------------------------------------------------------------
1 | EXETYPE NT
2 | SUBSYSTEM WINDOWS
--------------------------------------------------------------------------------
/examples/rx-dnd-gtkd/dub.sdl:
--------------------------------------------------------------------------------
1 | name "rx-dnd-gtkd"
2 | description "A minimal D application."
3 | authors "lempiji"
4 | dependency "rx" path="../../"
5 | dependency "gfm:math" version="~>8.0.6"
6 | dependency "gtk-d" version="~>3.10.0"
7 |
--------------------------------------------------------------------------------
/examples/rx-fswatch/data/data.txt:
--------------------------------------------------------------------------------
1 | TEST2
--------------------------------------------------------------------------------
/examples/rx-fswatch/dub.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "rx-fswatch",
3 | "authors": [
4 | "lempiji"
5 | ],
6 | "description": "A minimal D application.",
7 | "dependencies": {
8 | "fswatch": "*",
9 | "rx": {
10 | "path": "../../"
11 | }
12 | },
13 | "license": "MIT"
14 | }
--------------------------------------------------------------------------------
/examples/rx-fswatch/dub.selections.json:
--------------------------------------------------------------------------------
1 | {
2 | "fileVersion": 1,
3 | "versions": {
4 | "fswatch": "0.6.0",
5 | "rx": {"path":"../../"},
6 | "silly": "1.1.1"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/examples/rx-fswatch/source/app.d:
--------------------------------------------------------------------------------
1 | import core.thread;
2 | import core.time;
3 | import fswatch;
4 | import rx;
5 | import std.range : put;
6 | import std.stdio;
7 |
8 | void main()
9 | {
10 | auto watcher = defer!(FileChangeEvent[], (observer) {
11 | auto shutdown = false;
12 |
13 | auto thread = new Thread({
14 | try
15 | {
16 | auto watch = FileWatch("./data", true);
17 |
18 | while (!shutdown)
19 | {
20 | auto events = watch.getEvents();
21 | if (events.length > 0)
22 | {
23 | .put(observer, events);
24 | }
25 |
26 | Thread.sleep(100.msecs);
27 | }
28 | observer.completed();
29 | }
30 | catch (Exception e)
31 | {
32 | observer.failure(e);
33 | }
34 | });
35 | thread.start();
36 |
37 | return new AnonymousDisposable({ shutdown = true; });
38 | });
39 |
40 | auto flatten = watcher.map!(events => from(events)).merge();
41 | auto changes = flatten.groupBy!(event => event.path)
42 | .map!(o => o.debounce(2.seconds))
43 | .merge();
44 |
45 | // start FileWatch
46 | auto disposable = changes.doSubscribe((FileChangeEvent event) {
47 | writeln(event);
48 | });
49 |
50 | scope (exit)
51 | disposable.dispose();
52 |
53 | writeln("Plaese Enter to exit.");
54 | readln();
55 | }
56 |
--------------------------------------------------------------------------------
/examples/rx-gtk-d/dub.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "rx-gtk-d",
3 | "authors": [
4 | "lempiji"
5 | ],
6 | "description": "A minimal D application.",
7 | "copyright": "Copyright © 2017, lempiji",
8 | "license": "MIT",
9 | "dependencies": {
10 | "rx": {
11 | "path": "../../"
12 | },
13 | "gtk-d:gtkd": "~>3.10.0"
14 | }
15 | }
--------------------------------------------------------------------------------
/examples/rx-gtk-d/source/app.d:
--------------------------------------------------------------------------------
1 | import gio.Application : GioApplication = Application;
2 | import gtk.Application;
3 | import gtk.ApplicationWindow;
4 | import gtk.EventBox;
5 | import gtk.Entry;
6 | import gtk.Label;
7 | import gtk.Widget;
8 | import gtk.Button;
9 | import gtk.VBox;
10 |
11 | import core.time;
12 | import rx;
13 | import std.range : put;
14 |
15 | class MyApplication : ApplicationWindow
16 | {
17 | this(Application application)
18 | {
19 | super(application);
20 | setTitle("rx: Example");
21 | setDefaultSize(640, 480);
22 |
23 | auto vbox = new VBox(false, 0);
24 | auto desc = new Label("Label synchronize to Entry with delay");
25 | auto input = new Entry();
26 | auto noDelay = new Label("");
27 | auto delayed = new Label("");
28 | auto clearButton = new Button("Clear");
29 | auto detachButton = new Button("Detach");
30 |
31 | vbox.packStart(desc, false, false, 0);
32 | vbox.packStart(input, false, false, 0);
33 | vbox.packStart(noDelay, false, false, 0);
34 | vbox.packStart(delayed, false, false, 0);
35 | vbox.packStart(clearButton, false, false, 0);
36 | vbox.packStart(detachButton, false, false, 0);
37 | add(vbox);
38 |
39 | //Create two Observable, and delay one.
40 | auto changedText = input.changedAsObservable().map!(entry => entry.getText());
41 | auto delayedText = changedText.debounce(300.msecs);
42 |
43 | //Subscribe in the same way.
44 | auto d1 = changedText.doSubscribe((string text) { noDelay.setText(text); });
45 | auto d2 = delayedText.doSubscribe((string text) { delayed.setText(text); });
46 |
47 | clearButton.addOnClicked((Button _) { input.setText(""); });
48 | detachButton.addOnClicked((Button _) { d1.dispose(); d2.dispose(); });
49 |
50 | showAll();
51 | }
52 | }
53 |
54 | int main(string[] args)
55 | {
56 | auto application = new Application("rx.myapplication", GApplicationFlags.FLAGS_NONE);
57 | application.addOnActivate(delegate void(GioApplication app) {
58 | new MyApplication(application);
59 | });
60 | return application.run(args);
61 | }
62 |
63 | Observable!Entry changedAsObservable(Entry entry)
64 | {
65 | import gobject.Signals;
66 |
67 | return defer!Entry((Observer!Entry observer) {
68 | auto handleId = entry.addOnChanged(_ => .put(observer, entry));
69 | return new AnonymousDisposable({
70 | Signals.handlerDisconnect(entry, handleId);
71 | });
72 | }).observableObject!Entry();
73 | }
74 |
--------------------------------------------------------------------------------
/examples/scheduler-dlangui/dub.json:
--------------------------------------------------------------------------------
1 | {
2 | "authors": [
3 | "lempiji"
4 | ],
5 | "copyright": "Copyright © 2016, lempiji",
6 | "dependencies": {
7 | "dlangui": "~>0.9.188",
8 | "rx": {
9 | "path": "../../",
10 | "version": ">=0.0.0"
11 | }
12 | },
13 | "description": "A minimal D application.",
14 | "license": "MIT",
15 | "name": "scheduler-dlangui"
16 | }
--------------------------------------------------------------------------------
/examples/scheduler-dlangui/source/app.d:
--------------------------------------------------------------------------------
1 | import core.time;
2 | import std.datetime;
3 | import std.conv;
4 | import std.stdio;
5 |
6 | import dlangui;
7 | import rx;
8 |
9 | import utils;
10 |
11 | mixin APP_ENTRY_POINT;
12 |
13 | /// entry point for dlangui based application
14 | extern (C) int UIAppMain(string[] args)
15 | {
16 | auto window = createAppWindow();
17 |
18 | auto scheduler = new DlangUIScheduler();
19 | window.mainWidget.addChild(scheduler);
20 | currentScheduler = scheduler;
21 |
22 | auto label = window.mainWidget.childById!TextWidget("label");
23 | auto edit = window.mainWidget.childById!EditLine("edit");
24 |
25 | edit.contentChange.asObservable().debounce(dur!"msecs"(200)).doSubscribe((EditableContent _) {
26 | label.text = edit.text;
27 | });
28 |
29 | // show window
30 | window.show();
31 |
32 | // run message loop
33 | return Platform.instance.enterMessageLoop();
34 | }
35 |
36 | Window createAppWindow()
37 | {
38 | // create window
39 | Log.d("Creating window");
40 | if (!Platform.instance)
41 | {
42 | Log.e("Platform.instance is null!!!");
43 | }
44 |
45 | auto window = Platform.instance.createWindow("DlangUI with Rx", null);
46 | Log.d("Window created");
47 |
48 | // create some widget to show in window
49 | window.mainWidget = parseML(q{
50 | VerticalLayout {
51 | padding: 10
52 | layoutWidth: fill
53 | backgroundColor: "#C0E0E070" // semitransparent yellow background
54 |
55 | EditLine { id: edit; layoutWidth: fill }
56 | TextWidget { id: label; }
57 | }
58 | });
59 |
60 | return window;
61 | }
62 |
--------------------------------------------------------------------------------
/examples/scheduler-dlangui/source/utils.d:
--------------------------------------------------------------------------------
1 | module utils;
2 |
3 | import core.time;
4 | import std.traits;
5 | import rx;
6 | import dlangui.core.signals;
7 | import dlangui.widgets.widget;
8 |
9 | ///Wrap a Signal!T as Observable
10 | auto asObservable(T)(ref T signal) if (is(T == Signal!U, U) && is(U == interface))
11 | {
12 | static if (is(T == Signal!U, U))
13 | {
14 | alias return_t = ReturnType!(__traits(getMember, U, __traits(allMembers, U)[0]));
15 | alias param_t = ParameterTypeTuple!(__traits(getMember, U, __traits(allMembers, U)[0]));
16 | static assert(param_t.length == 1);
17 | }
18 |
19 | static struct LocalObservable
20 | {
21 | alias ElementType = param_t[0];
22 | this(ref T signal)
23 | {
24 | _subscribe = (Observer!ElementType o) {
25 | auto dg = (ElementType w) {
26 | o.put(w);
27 | static if (is(return_t == bool))
28 | {
29 | return true;
30 | }
31 | };
32 |
33 | signal.connect(dg);
34 |
35 | return new AnonymousDisposable({ signal.disconnect(dg); });
36 | };
37 | }
38 |
39 | auto subscribe(U)(U observer)
40 | {
41 | return _subscribe(observerObject!ElementType(observer));
42 | }
43 |
44 | Disposable delegate(Observer!ElementType) _subscribe;
45 | }
46 |
47 | return LocalObservable(signal);
48 | }
49 |
50 | struct TimerHandler
51 | {
52 | CancellationToken token;
53 | void delegate() action;
54 | }
55 |
56 | class DlangUIScheduler : Widget, Scheduler
57 | {
58 | TimerHandler[ulong] _actions;
59 | Object _gate = new Object();
60 | ulong _timerId;
61 |
62 | CancellationToken schedule(void delegate() op, Duration val)
63 | {
64 | auto ms = val.total!"msecs";
65 | auto id = setTimer(ms);
66 | auto token = new CancellationToken();
67 | synchronized (_gate)
68 | {
69 | _actions[id] = TimerHandler(token, op);
70 | }
71 | return token;
72 | }
73 |
74 | override bool onTimer(ulong id)
75 | {
76 | CancellationToken token;
77 | void delegate() action;
78 |
79 | synchronized (_gate)
80 | {
81 | auto temp = id in _actions;
82 | if (temp)
83 | {
84 | token = (*temp).token;
85 | action = (*temp).action;
86 |
87 | _actions.remove(id);
88 | }
89 | else
90 | {
91 | return false;
92 | }
93 | }
94 |
95 | if (token is null || !token.isCanceled)
96 | {
97 | action();
98 | return true;
99 | }
100 |
101 | return false;
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/examples/scheduler-dlangui/source/win_app.def:
--------------------------------------------------------------------------------
1 | EXETYPE NT
2 | SUBSYSTEM WINDOWS
--------------------------------------------------------------------------------
/source/rx/algorithm/fold.d:
--------------------------------------------------------------------------------
1 | /+++++++++++++++++++++++++++++
2 | + This module defines algorithm 'fold'
3 | +/
4 | module rx.algorithm.fold;
5 |
6 | import rx.disposable;
7 | import rx.observable;
8 | import rx.observer;
9 |
10 | //####################
11 | // Fold
12 | //####################
13 | ///
14 | auto fold(alias fun, TObservable, Seed)(auto ref TObservable observable, Seed seed)
15 | {
16 | import rx.algorithm : scan;
17 | import rx.range : takeLast;
18 |
19 | return observable.scan!fun(seed).takeLast;
20 | }
21 | ///
22 | unittest
23 | {
24 | import rx.subject : SubjectObject;
25 |
26 | auto sub = new SubjectObject!int;
27 | auto sum = sub.fold!"a+b"(0);
28 |
29 | int result = 0;
30 | auto disposable = sum.doSubscribe((int n) { result = n; });
31 | scope (exit)
32 | disposable.dispose();
33 |
34 | foreach (i; 1 .. 11)
35 | sub.put(i);
36 |
37 | assert(result == 0);
38 | sub.completed();
39 | assert(result == 55);
40 | }
41 |
--------------------------------------------------------------------------------
/source/rx/algorithm/package.d:
--------------------------------------------------------------------------------
1 | module rx.algorithm;
2 |
3 | public import rx.algorithm.all;
4 | public import rx.algorithm.any;
5 | public import rx.algorithm.buffer;
6 | public import rx.algorithm.combineLatest;
7 | public import rx.algorithm.debounce;
8 | public import rx.algorithm.filter;
9 | public import rx.algorithm.fold;
10 | public import rx.algorithm.groupby;
11 | public import rx.algorithm.map;
12 | public import rx.algorithm.merge;
13 | public import rx.algorithm.scan;
14 | public import rx.algorithm.tee;
15 | public import rx.algorithm.uniq;
16 |
17 | //####################
18 | // Overview
19 | //####################
20 | ///
21 | unittest
22 | {
23 | import rx;
24 | import std.conv : to;
25 | import std.range : iota, put;
26 |
27 | auto subject = new SubjectObject!int;
28 |
29 | string[] result;
30 | auto disposable = subject.filter!(n => n % 2 == 0).map!(o => to!string(o))
31 | .doSubscribe!(text => result ~= text);
32 |
33 | scope (exit)
34 | disposable.dispose();
35 |
36 | put(subject, iota(10));
37 |
38 | assert(result == ["0", "2", "4", "6", "8"]);
39 | }
40 |
41 | ///
42 | unittest
43 | {
44 | import rx;
45 |
46 | auto sub = new SubjectObject!int;
47 |
48 | auto hasEven = sub.any!"a % 2 == 0"();
49 | auto result = false;
50 | auto disposable = hasEven.doSubscribe((bool b) { result = b; });
51 | scope (exit)
52 | disposable.dispose();
53 |
54 | sub.put(1);
55 | sub.put(3);
56 | sub.put(2);
57 | assert(result);
58 | }
59 |
--------------------------------------------------------------------------------
/source/rx/package.d:
--------------------------------------------------------------------------------
1 | module rx;
2 |
3 | public import rx.disposable;
4 | public import rx.observer;
5 | public import rx.observable;
6 | public import rx.subject;
7 | public import rx.scheduler;
8 | public import rx.range;
9 | public import rx.algorithm;
10 | public import rx.util;
11 |
--------------------------------------------------------------------------------
/source/rx/range/package.d:
--------------------------------------------------------------------------------
1 | module rx.range;
2 |
3 | public import rx.range.drop;
4 | public import rx.range.take;
5 | public import rx.range.takeLast;
6 | public import rx.range.takeUntil;
7 | public import rx.range.zip;
8 |
9 | /+++++++++++++++++++++++++++++
10 | + Overview
11 | +/
12 | unittest
13 | {
14 | import rx : SubjectObject, observerObject, drop, take;
15 | import std.algorithm : equal;
16 | import std.array : appender;
17 | import std.conv : to;
18 |
19 | auto subject = new SubjectObject!int;
20 | auto pub = subject.drop(2).take(3);
21 |
22 | auto buf = appender!(int[]);
23 | auto disposable = pub.subscribe(observerObject!int(buf));
24 |
25 | foreach (i; 0 .. 10)
26 | {
27 | subject.put(i);
28 | }
29 |
30 | auto result = buf.data;
31 | assert(equal(result, [2, 3, 4]));
32 | }
33 |
--------------------------------------------------------------------------------
/source/rx/range/takeUntil.d:
--------------------------------------------------------------------------------
1 | /+++++++++++++++++++++++++++++
2 | + This module is a submodule of rx.range.
3 | + It provides basic operation a 'takeUntil'
4 | +/
5 | module rx.range.takeUntil;
6 |
7 | import rx.disposable;
8 | import rx.observer;
9 | import rx.observable;
10 | import rx.util;
11 |
12 | import std.range : put;
13 |
14 | //####################
15 | // TakeUntil
16 | //####################
17 | ///
18 | auto takeUntil(TObservable1, TObservable2)(auto ref TObservable1 source, auto ref TObservable2 stopper)
19 | if (isObservable!TObservable1 && isObservable!TObservable2)
20 | {
21 | static struct TakeUntilObservable
22 | {
23 | alias ElementType = TObservable1.ElementType;
24 |
25 | TObservable1 source;
26 | TObservable2 stopper;
27 |
28 | auto subscribe(TObserver)(auto ref TObserver observer)
29 | {
30 | auto sourceDisposable = source.doSubscribe(observer);
31 | auto stopperDisposable = stopper.doSubscribe((TObservable2.ElementType _) {
32 | static if (hasCompleted!TObserver)
33 | {
34 | observer.completed();
35 | }
36 | sourceDisposable.dispose();
37 | });
38 |
39 | return new CompositeDisposable(sourceDisposable, stopperDisposable);
40 | }
41 | }
42 |
43 | return TakeUntilObservable(source, stopper);
44 | }
45 |
46 | ///
47 | unittest
48 | {
49 | import std.algorithm;
50 | import rx;
51 |
52 | auto source = new SubjectObject!int;
53 | auto stopper = new SubjectObject!int;
54 |
55 | int[] buf;
56 | auto disposable = source.takeUntil(stopper).doSubscribe!((n) { buf ~= n; });
57 |
58 | source.put(0);
59 | source.put(1);
60 | source.put(2);
61 |
62 | stopper.put(0);
63 |
64 | source.put(3);
65 | source.put(4);
66 |
67 | assert(equal(buf, [0, 1, 2]));
68 | }
69 |
70 | unittest
71 | {
72 | import std.algorithm;
73 | import rx;
74 |
75 | auto sub1 = new SubjectObject!int;
76 | auto sub2 = new SubjectObject!int;
77 |
78 | int[] buf;
79 | auto disposable = sub1.takeUntil(sub2).subscribe((int n) { buf ~= n; });
80 |
81 | sub1.put(0);
82 |
83 | disposable.dispose();
84 |
85 | sub1.put(1);
86 |
87 | assert(equal(buf, [0]));
88 | }
89 |
--------------------------------------------------------------------------------