on e461b17 help sign in
.travis.yml+12−18
since splitsnapshots
unifiedsplit
@@ -25,30 +25,24 @@ matrix:
25 - name: "build (beta)"
25 - name: "build (beta)"
26 rust: beta
26 rust: beta
27 script: INSTALL=1 ./build.sh
27 script: INSTALL=1 ./build.sh
28+ - name: "build (nightly)"
29+ rust: nightly
30+ script: INSTALL=1 ./build.sh
28 - name: "headless browser tests (firefox)"
31 - name: "headless browser tests (firefox)"
29 rust: stable
32 rust: stable
30 addons:
33 addons:
31 firefox: latest
34 firefox: latest
32 script: wasm-pack test --firefox --headless -- --features xxx-unstable-internal-use-only
35 script: wasm-pack test --firefox --headless -- --features xxx-unstable-internal-use-only
36+ - name: "headless browser tests (chrome)"
37+ rust: stable
38+ addons:
39+ chrome: stable
40+ script: wasm-pack test --chrome --headless -- --features xxx-unstable-internal-use-only
33 - name: "native tests"
41 - name: "native tests"
34 rust: stable
42 rust: stable
35 install: echo "no install"
43 install: echo "no install"
36 script: cargo test --all
44 script: cargo test --all
37−
38− # TODO: A bug in `rustc` is making `js-sys` broken on nightly:
39− # https://github.com/rust-lang/rust/issues/69315
40− # - name: "build (nightly)"
41− # rust: nightly
42− # script: INSTALL=1 ./build.sh
43− # - name: "check native benches"
45+ - name: "check native benches"
44− # rust: nightly
46+ rust: nightly
45− # install: echo "no install"
47+ install: echo "no install"
46− # script: cargo check --benches --features xxx-unstable-internal-use-only
48+ script: cargo check --benches --features xxx-unstable-internal-use-only
47−
48− # TODO: `chromedriver` is complaining about ports or something. Temporarily
49− # disable in CI until we figure it out.
50− # - name: "headless browser tests (chrome)"
51− # rust: stable
52− # addons:
53− # chrome: stable
54− # script: wasm-pack test --chrome --headless -- --features xxx-unstable-internal-use-only
Cargo.lock+504−500
@@ -1,71 +1,104 @@
1# This file is automatically @generated by Cargo.
1# This file is automatically @generated by Cargo.
2# It is not intended for manual editing.
2# It is not intended for manual editing.
3[[package]]
3[[package]]
4−name = "anyhow"
4+name = "aho-corasick"
5−version = "1.0.25"
5+version = "0.7.3"
6source = "registry+https://github.com/rust-lang/crates.io-index"
6source = "registry+https://github.com/rust-lang/crates.io-index"
7+dependencies = [
8+ "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
9+]
10+
11+[[package]]
12+name = "arrayvec"
13+version = "0.4.10"
14+source = "registry+https://github.com/rust-lang/crates.io-index"
15+dependencies = [
16+ "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
17+]
7
18
8[[package]]
19[[package]]
9name = "atty"
20name = "atty"
10−version = "0.2.13"
21+version = "0.2.11"
11source = "registry+https://github.com/rust-lang/crates.io-index"
22source = "registry+https://github.com/rust-lang/crates.io-index"
12dependencies = [
23dependencies = [
24+ "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
13− "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
25+ "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
14− "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
26+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
15]
27]
16
28
17[[package]]
29[[package]]
18name = "autocfg"
30name = "autocfg"
19−version = "0.1.7"
31+version = "0.1.2"
20source = "registry+https://github.com/rust-lang/crates.io-index"
32source = "registry+https://github.com/rust-lang/crates.io-index"
21
33
22[[package]]
34[[package]]
23−name = "bitflags"
35+name = "backtrace"
24−version = "1.2.1"
36+version = "0.3.15"
25source = "registry+https://github.com/rust-lang/crates.io-index"
37source = "registry+https://github.com/rust-lang/crates.io-index"
38+dependencies = [
39+ "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
40+ "backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
41+ "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
42+ "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
43+ "rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
44+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
45+]
26
46
27[[package]]
47[[package]]
28−name = "bstr"
48+name = "backtrace-sys"
29−version = "0.2.8"
49+version = "0.1.28"
30source = "registry+https://github.com/rust-lang/crates.io-index"
50source = "registry+https://github.com/rust-lang/crates.io-index"
31dependencies = [
51dependencies = [
32− "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
33− "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
52+ "cc 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)",
34− "regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
35− "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)",
53+ "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
36]
54]
37
55
56+[[package]]
57+name = "bitflags"
58+version = "1.0.4"
59+source = "registry+https://github.com/rust-lang/crates.io-index"
60+
38[[package]]
61[[package]]
39name = "bumpalo"
62name = "bumpalo"
40−version = "2.6.0"
63+version = "2.4.1"
41source = "registry+https://github.com/rust-lang/crates.io-index"
64source = "registry+https://github.com/rust-lang/crates.io-index"
42
65
43[[package]]
66[[package]]
44name = "byteorder"
67name = "byteorder"
45−version = "1.3.2"
68+version = "1.3.1"
46source = "registry+https://github.com/rust-lang/crates.io-index"
69source = "registry+https://github.com/rust-lang/crates.io-index"
47
70
48[[package]]
71[[package]]
49name = "cast"
72name = "cast"
50−version = "0.2.3"
73+version = "0.2.2"
74+source = "registry+https://github.com/rust-lang/crates.io-index"
75+
76+[[package]]
77+name = "cc"
78+version = "1.0.34"
51source = "registry+https://github.com/rust-lang/crates.io-index"
79source = "registry+https://github.com/rust-lang/crates.io-index"
52−dependencies = [
53− "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
54−]
55
80
56[[package]]
81[[package]]
57name = "cfg-if"
82name = "cfg-if"
58−version = "0.1.10"
83+version = "0.1.7"
59source = "registry+https://github.com/rust-lang/crates.io-index"
84source = "registry+https://github.com/rust-lang/crates.io-index"
60
85
61[[package]]
86[[package]]
62name = "clap"
87name = "clap"
63−version = "2.33.0"
88+version = "2.32.0"
64source = "registry+https://github.com/rust-lang/crates.io-index"
89source = "registry+https://github.com/rust-lang/crates.io-index"
65dependencies = [
90dependencies = [
66− "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
91+ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
67− "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
92+ "textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
93+ "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
94+]
95+
96+[[package]]
97+name = "cloudabi"
98+version = "0.0.3"
99+source = "registry+https://github.com/rust-lang/crates.io-index"
100+dependencies = [
68− "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
101+ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
69]
102]
70
103
71[[package]]
104[[package]]
@@ -73,132 +106,122 @@ name = "console_error_panic_hook"
73version = "0.1.6"
106version = "0.1.6"
74source = "registry+https://github.com/rust-lang/crates.io-index"
107source = "registry+https://github.com/rust-lang/crates.io-index"
75dependencies = [
108dependencies = [
76− "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
109+ "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
77− "wasm-bindgen 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)",
110+ "wasm-bindgen 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
78]
111]
79
112
80[[package]]
113[[package]]
81name = "console_log"
114name = "console_log"
82−version = "0.2.0"
115+version = "0.1.2"
83source = "registry+https://github.com/rust-lang/crates.io-index"
116source = "registry+https://github.com/rust-lang/crates.io-index"
84dependencies = [
117dependencies = [
85− "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
118+ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
86− "web-sys 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)",
119+ "web-sys 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
87]
120]
88
121
89[[package]]
122[[package]]
90name = "criterion"
123name = "criterion"
91−version = "0.3.3"
124+version = "0.2.11"
92−source = "registry+https://github.com/rust-lang/crates.io-index"
125+source = "registry+https://github.com/rust-lang/crates.io-index"
93−dependencies = [
126+dependencies = [
94− "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)",
127+ "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
95− "cast 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
128+ "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
96− "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
129+ "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
97− "criterion-plot 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
130+ "criterion-plot 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
98− "csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
131+ "csv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
99− "itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
132+ "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
133+ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
100− "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
134+ "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
101− "num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
135+ "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
136+ "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
102− "oorandom 11.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
137+ "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
103− "plotters 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
138+ "rand_xoshiro 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
104− "rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
139+ "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
105− "regex 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
140+ "rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
106− "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)",
107− "serde_cbor 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)",
141+ "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
108− "serde_derive 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)",
142+ "serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
109− "serde_json 1.0.57 (registry+https://github.com/rust-lang/crates.io-index)",
143+ "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
110− "tinytemplate 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
144+ "tinytemplate 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
111− "walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
145+ "walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
112]
146]
113
147
114[[package]]
148[[package]]
115name = "criterion-plot"
149name = "criterion-plot"
116−version = "0.4.3"
150+version = "0.3.1"
117source = "registry+https://github.com/rust-lang/crates.io-index"
151source = "registry+https://github.com/rust-lang/crates.io-index"
118dependencies = [
152dependencies = [
153+ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
119− "cast 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
154+ "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
120− "itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
155+ "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
121]
156]
122
157
123[[package]]
158[[package]]
124name = "crossbeam-deque"
159name = "crossbeam-deque"
125−version = "0.7.2"
160+version = "0.2.0"
126source = "registry+https://github.com/rust-lang/crates.io-index"
161source = "registry+https://github.com/rust-lang/crates.io-index"
127dependencies = [
162dependencies = [
128− "crossbeam-epoch 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
163+ "crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
129− "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
164+ "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
130]
165]
131
166
132[[package]]
167[[package]]
133name = "crossbeam-epoch"
168name = "crossbeam-epoch"
134−version = "0.8.0"
169+version = "0.3.1"
135−source = "registry+https://github.com/rust-lang/crates.io-index"
136−dependencies = [
137− "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
138− "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
139− "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
140− "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
141− "memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
142− "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
143−]
144−
145−[[package]]
146−name = "crossbeam-queue"
147−version = "0.2.0"
148source = "registry+https://github.com/rust-lang/crates.io-index"
170source = "registry+https://github.com/rust-lang/crates.io-index"
149dependencies = [
171dependencies = [
172+ "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
173+ "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
174+ "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
175+ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
176+ "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
177+ "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
150− "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
178+ "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
151]
179]
152
180
153[[package]]
181[[package]]
154name = "crossbeam-utils"
182name = "crossbeam-utils"
155−version = "0.7.0"
183+version = "0.2.2"
156source = "registry+https://github.com/rust-lang/crates.io-index"
184source = "registry+https://github.com/rust-lang/crates.io-index"
157dependencies = [
185dependencies = [
158− "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
159− "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
160− "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
186+ "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
161]
187]
162
188
163[[package]]
189[[package]]
164name = "csv"
190name = "csv"
165−version = "1.1.1"
191+version = "1.0.5"
166source = "registry+https://github.com/rust-lang/crates.io-index"
192source = "registry+https://github.com/rust-lang/crates.io-index"
167dependencies = [
193dependencies = [
168− "bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
169− "csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
170− "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
171− "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
194+ "csv-core 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
172− "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)",
195+ "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
173]
196]
174
197
175[[package]]
198[[package]]
176name = "csv-core"
199name = "csv-core"
177−version = "0.1.6"
200+version = "0.1.5"
178source = "registry+https://github.com/rust-lang/crates.io-index"
201source = "registry+https://github.com/rust-lang/crates.io-index"
179dependencies = [
202dependencies = [
180− "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
203+ "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
181]
204]
182
205
183[[package]]
206[[package]]
184name = "dodrio"
207name = "dodrio"
185−version = "0.2.0"
208+version = "0.1.0"
186dependencies = [
209dependencies = [
210+ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
187− "bumpalo 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
211+ "bumpalo 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
188− "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
212+ "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
189− "console_log 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
213+ "console_log 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
190− "criterion 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
214+ "criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
191− "dodrio-js-api 0.2.0",
215+ "dodrio-js-api 0.1.0",
192− "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
216+ "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
193 "fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
217 "fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
194− "js-sys 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)",
218+ "js-sys 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
195− "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
219+ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
196 "longest-increasing-subsequence 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
220 "longest-increasing-subsequence 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
197− "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)",
198− "wasm-bindgen 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)",
221+ "wasm-bindgen 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
199− "wasm-bindgen-futures 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
222+ "wasm-bindgen-futures 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
200− "wasm-bindgen-test 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
223+ "wasm-bindgen-test 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
201− "web-sys 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)",
224+ "web-sys 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
202]
225]
203
226
204[[package]]
227[[package]]
@@ -206,12 +229,12 @@ name = "dodrio-counter"
206version = "0.1.0"
229version = "0.1.0"
207dependencies = [
230dependencies = [
208 "console_error_panic_hook 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
231 "console_error_panic_hook 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
209− "console_log 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
232+ "console_log 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
210− "dodrio 0.2.0",
233+ "dodrio 0.1.0",
211− "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
234+ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
212− "wasm-bindgen 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)",
235+ "wasm-bindgen 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
213− "wasm-bindgen-test 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
236+ "wasm-bindgen-test 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
214− "web-sys 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)",
237+ "web-sys 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
215]
238]
216
239
217[[package]]
240[[package]]
@@ -219,12 +242,13 @@ name = "dodrio-game-of-life"
219version = "0.1.0"
242version = "0.1.0"
220dependencies = [
243dependencies = [
221 "console_error_panic_hook 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
244 "console_error_panic_hook 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
222− "dodrio 0.2.0",
245+ "dodrio 0.1.0",
246+ "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
223− "js-sys 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)",
247+ "js-sys 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
224− "wasm-bindgen 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)",
248+ "wasm-bindgen 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
225− "wasm-bindgen-futures 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
249+ "wasm-bindgen-futures 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
226− "wasm-bindgen-test 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
250+ "wasm-bindgen-test 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
227− "web-sys 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)",
251+ "web-sys 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
228]
252]
229
253
230[[package]]
254[[package]]
@@ -232,10 +256,10 @@ name = "dodrio-hello-world"
232version = "0.1.0"
256version = "0.1.0"
233dependencies = [
257dependencies = [
234 "console_error_panic_hook 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
258 "console_error_panic_hook 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
235− "dodrio 0.2.0",
259+ "dodrio 0.1.0",
236− "wasm-bindgen 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)",
260+ "wasm-bindgen 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
237− "wasm-bindgen-test 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
261+ "wasm-bindgen-test 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
238− "web-sys 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)",
262+ "web-sys 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
239]
263]
240
264
241[[package]]
265[[package]]
@@ -243,21 +267,22 @@ name = "dodrio-input-form"
243version = "0.1.0"
267version = "0.1.0"
244dependencies = [
268dependencies = [
245 "console_error_panic_hook 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
269 "console_error_panic_hook 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
246− "dodrio 0.2.0",
270+ "dodrio 0.1.0",
247− "wasm-bindgen 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)",
271+ "wasm-bindgen 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
248− "wasm-bindgen-test 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
272+ "wasm-bindgen-test 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
249− "web-sys 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)",
273+ "web-sys 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
250]
274]
251
275
252[[package]]
276[[package]]
253name = "dodrio-js-api"
277name = "dodrio-js-api"
254−version = "0.2.0"
278+version = "0.1.0"
255dependencies = [
279dependencies = [
256− "dodrio 0.2.0",
280+ "dodrio 0.1.0",
281+ "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
257− "js-sys 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)",
282+ "js-sys 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
258− "wasm-bindgen 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)",
283+ "wasm-bindgen 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
259− "wasm-bindgen-futures 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
284+ "wasm-bindgen-futures 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
260− "wasm-bindgen-test 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
285+ "wasm-bindgen-test 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
261]
286]
262
287
263[[package]]
288[[package]]
@@ -265,27 +290,28 @@ name = "dodrio-js-component"
265version = "0.1.0"
290version = "0.1.0"
266dependencies = [
291dependencies = [
267 "console_error_panic_hook 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
292 "console_error_panic_hook 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
268− "dodrio 0.2.0",
293+ "dodrio 0.1.0",
269− "dodrio-js-api 0.2.0",
294+ "dodrio-js-api 0.1.0",
270− "js-sys 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)",
295+ "js-sys 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
271− "wasm-bindgen 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)",
296+ "wasm-bindgen 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
272− "web-sys 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)",
297+ "web-sys 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
273]
298]
274
299
275[[package]]
300[[package]]
276name = "dodrio-moire"
301name = "dodrio-moire"
277version = "0.1.0"
302version = "0.1.0"
278dependencies = [
303dependencies = [
279− "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
304+ "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
280 "console_error_panic_hook 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
305 "console_error_panic_hook 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
281− "console_log 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
306+ "console_log 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
282− "dodrio 0.2.0",
307+ "dodrio 0.1.0",
308+ "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
283− "js-sys 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)",
309+ "js-sys 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
284− "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
310+ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
285− "wasm-bindgen 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)",
311+ "wasm-bindgen 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
286− "wasm-bindgen-futures 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
312+ "wasm-bindgen-futures 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
287− "wasm-bindgen-test 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
313+ "wasm-bindgen-test 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
288− "web-sys 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)",
314+ "web-sys 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
289]
315]
290
316
291[[package]]
317[[package]]
@@ -293,189 +319,142 @@ name = "dodrio-sierpinski"
293version = "0.1.0"
319version = "0.1.0"
294dependencies = [
320dependencies = [
295 "console_error_panic_hook 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
321 "console_error_panic_hook 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
296− "dodrio 0.2.0",
322+ "dodrio 0.1.0",
323+ "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
297− "js-sys 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)",
324+ "js-sys 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
298− "wasm-bindgen 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)",
325+ "wasm-bindgen 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
299− "wasm-bindgen-futures 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
326+ "wasm-bindgen-futures 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
300− "wasm-bindgen-test 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
327+ "wasm-bindgen-test 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
301− "web-sys 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)",
328+ "web-sys 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
302]
329]
303
330
304[[package]]
331[[package]]
305name = "dodrio-todomvc"
332name = "dodrio-todomvc"
306version = "0.1.0"
333version = "0.1.0"
307dependencies = [
334dependencies = [
308− "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
335+ "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
309 "console_error_panic_hook 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
336 "console_error_panic_hook 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
310− "console_log 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
337+ "console_log 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
311− "dodrio 0.2.0",
338+ "dodrio 0.1.0",
339+ "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
312− "js-sys 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)",
340+ "js-sys 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
313− "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
341+ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
314− "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)",
342+ "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
315− "serde_json 1.0.57 (registry+https://github.com/rust-lang/crates.io-index)",
343+ "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
316− "wasm-bindgen 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)",
344+ "wasm-bindgen 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
317− "wasm-bindgen-futures 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
345+ "wasm-bindgen-futures 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
318− "wasm-bindgen-test 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
346+ "wasm-bindgen-test 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
319− "web-sys 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)",
347+ "web-sys 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
320]
348]
321
349
322[[package]]
350[[package]]
323name = "either"
351name = "either"
324−version = "1.5.3"
352+version = "1.5.2"
325source = "registry+https://github.com/rust-lang/crates.io-index"
353source = "registry+https://github.com/rust-lang/crates.io-index"
326
354
327[[package]]
355[[package]]
328−name = "futures"
356+name = "env_logger"
329−version = "0.3.5"
357+version = "0.6.1"
330source = "registry+https://github.com/rust-lang/crates.io-index"
358source = "registry+https://github.com/rust-lang/crates.io-index"
331dependencies = [
359dependencies = [
332− "futures-channel 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
360+ "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
333− "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
334− "futures-executor 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
361+ "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
335− "futures-io 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
362+ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
336− "futures-sink 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
363+ "regex 1.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
337− "futures-task 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
338− "futures-util 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
364+ "termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
339]
365]
340
366
341[[package]]
367[[package]]
342−name = "futures-channel"
368+name = "failure"
343−version = "0.3.5"
369+version = "0.1.5"
344−source = "registry+https://github.com/rust-lang/crates.io-index"
345−dependencies = [
346− "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
347− "futures-sink 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
348−]
349−
350−[[package]]
351−name = "futures-core"
352−version = "0.3.5"
353−source = "registry+https://github.com/rust-lang/crates.io-index"
354−
355−[[package]]
356−name = "futures-executor"
357−version = "0.3.5"
358source = "registry+https://github.com/rust-lang/crates.io-index"
370source = "registry+https://github.com/rust-lang/crates.io-index"
359dependencies = [
371dependencies = [
360− "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
372+ "backtrace 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
361− "futures-task 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
362− "futures-util 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
373+ "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
363]
374]
364
375
365[[package]]
376[[package]]
366−name = "futures-io"
377+name = "failure_derive"
367−version = "0.3.5"
368−source = "registry+https://github.com/rust-lang/crates.io-index"
369−
370−[[package]]
371−name = "futures-macro"
372−version = "0.3.5"
378+version = "0.1.5"
373source = "registry+https://github.com/rust-lang/crates.io-index"
379source = "registry+https://github.com/rust-lang/crates.io-index"
374dependencies = [
380dependencies = [
375− "proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)",
376− "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
381+ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
377− "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
382+ "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
383+ "syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)",
378− "syn 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)",
384+ "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
379]
385]
380
386
381[[package]]
387[[package]]
382−name = "futures-sink"
388+name = "fuchsia-cprng"
383−version = "0.3.5"
389+version = "0.1.1"
384source = "registry+https://github.com/rust-lang/crates.io-index"
390source = "registry+https://github.com/rust-lang/crates.io-index"
385
391
386[[package]]
392[[package]]
387−name = "futures-task"
393+name = "futures"
388−version = "0.3.5"
394+version = "0.1.26"
389−source = "registry+https://github.com/rust-lang/crates.io-index"
390−dependencies = [
391− "once_cell 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
392−]
393−
394−[[package]]
395−name = "futures-util"
396−version = "0.3.5"
397source = "registry+https://github.com/rust-lang/crates.io-index"
395source = "registry+https://github.com/rust-lang/crates.io-index"
398−dependencies = [
399− "futures-channel 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
400− "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
401− "futures-io 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
402− "futures-macro 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
403− "futures-sink 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
404− "futures-task 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
405− "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
406− "pin-project 0.4.16 (registry+https://github.com/rust-lang/crates.io-index)",
407− "pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
408− "proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)",
409− "proc-macro-nested 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
410− "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
411−]
412
396
413[[package]]
397[[package]]
414name = "fxhash"
398name = "fxhash"
415version = "0.2.1"
399version = "0.2.1"
416source = "registry+https://github.com/rust-lang/crates.io-index"
400source = "registry+https://github.com/rust-lang/crates.io-index"
417dependencies = [
401dependencies = [
418− "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
402+ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
419]
403]
420
404
421−[[package]]
422−name = "half"
423−version = "1.6.0"
424−source = "registry+https://github.com/rust-lang/crates.io-index"
425−
426[[package]]
405[[package]]
427name = "heck"
406name = "heck"
428version = "0.3.1"
407version = "0.3.1"
429source = "registry+https://github.com/rust-lang/crates.io-index"
408source = "registry+https://github.com/rust-lang/crates.io-index"
430dependencies = [
409dependencies = [
431− "unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
410+ "unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
432]
411]
433
412
434[[package]]
413[[package]]
435−name = "hermit-abi"
414+name = "humantime"
436−version = "0.1.3"
415+version = "1.2.0"
437source = "registry+https://github.com/rust-lang/crates.io-index"
416source = "registry+https://github.com/rust-lang/crates.io-index"
438dependencies = [
417dependencies = [
439− "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
418+ "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
440]
419]
441
420
442[[package]]
421[[package]]
443name = "itertools"
422name = "itertools"
444−version = "0.9.0"
423+version = "0.8.0"
445source = "registry+https://github.com/rust-lang/crates.io-index"
424source = "registry+https://github.com/rust-lang/crates.io-index"
446dependencies = [
425dependencies = [
447− "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
426+ "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
448]
427]
449
428
450[[package]]
429[[package]]
451name = "itoa"
430name = "itoa"
452−version = "0.4.4"
431+version = "0.4.3"
453source = "registry+https://github.com/rust-lang/crates.io-index"
432source = "registry+https://github.com/rust-lang/crates.io-index"
454
433
455[[package]]
434[[package]]
456name = "js-sys"
435name = "js-sys"
457−version = "0.3.32"
436+version = "0.3.19"
458source = "registry+https://github.com/rust-lang/crates.io-index"
437source = "registry+https://github.com/rust-lang/crates.io-index"
459dependencies = [
438dependencies = [
460− "wasm-bindgen 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)",
439+ "wasm-bindgen 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
461]
440]
462
441
463[[package]]
442[[package]]
464name = "lazy_static"
443name = "lazy_static"
465−version = "1.4.0"
444+version = "1.3.0"
466source = "registry+https://github.com/rust-lang/crates.io-index"
445source = "registry+https://github.com/rust-lang/crates.io-index"
467
446
468[[package]]
447[[package]]
469name = "libc"
448name = "libc"
470−version = "0.2.66"
449+version = "0.2.51"
471source = "registry+https://github.com/rust-lang/crates.io-index"
450source = "registry+https://github.com/rust-lang/crates.io-index"
472
451
473[[package]]
452[[package]]
474name = "log"
453name = "log"
475−version = "0.4.11"
454+version = "0.4.6"
476source = "registry+https://github.com/rust-lang/crates.io-index"
455source = "registry+https://github.com/rust-lang/crates.io-index"
477dependencies = [
456dependencies = [
478− "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
457+ "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
479]
458]
480
459
481[[package]]
460[[package]]
@@ -485,180 +464,175 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
485
464
486[[package]]
465[[package]]
487name = "memchr"
466name = "memchr"
488−version = "2.2.1"
467+version = "2.2.0"
489source = "registry+https://github.com/rust-lang/crates.io-index"
468source = "registry+https://github.com/rust-lang/crates.io-index"
490dependencies = [
469dependencies = [
491− "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
470+ "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
492]
471]
493
472
494[[package]]
473[[package]]
495name = "memoffset"
474name = "memoffset"
496−version = "0.5.3"
475+version = "0.2.1"
476+source = "registry+https://github.com/rust-lang/crates.io-index"
477+
478+[[package]]
479+name = "nodrop"
480+version = "0.1.13"
497source = "registry+https://github.com/rust-lang/crates.io-index"
481source = "registry+https://github.com/rust-lang/crates.io-index"
498−dependencies = [
499− "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
500−]
501
482
502[[package]]
483[[package]]
503name = "nom"
484name = "nom"
504version = "4.2.3"
485version = "4.2.3"
505source = "registry+https://github.com/rust-lang/crates.io-index"
486source = "registry+https://github.com/rust-lang/crates.io-index"
506dependencies = [
487dependencies = [
507− "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
488+ "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
508 "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
489 "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
509]
490]
510
491
511[[package]]
492[[package]]
512name = "num-traits"
493name = "num-traits"
513−version = "0.2.10"
494+version = "0.2.6"
514source = "registry+https://github.com/rust-lang/crates.io-index"
495source = "registry+https://github.com/rust-lang/crates.io-index"
515−dependencies = [
516− "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
517−]
518
496
519[[package]]
497[[package]]
520name = "num_cpus"
498name = "num_cpus"
521−version = "1.11.1"
499+version = "1.10.0"
522source = "registry+https://github.com/rust-lang/crates.io-index"
500source = "registry+https://github.com/rust-lang/crates.io-index"
523dependencies = [
501dependencies = [
524− "hermit-abi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
525− "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
502+ "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
526]
503]
527
504
528[[package]]
505[[package]]
529−name = "once_cell"
506+name = "proc-macro2"
530−version = "1.3.1"
507+version = "0.4.27"
531source = "registry+https://github.com/rust-lang/crates.io-index"
508source = "registry+https://github.com/rust-lang/crates.io-index"
509+dependencies = [
510+ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
511+]
532
512
533[[package]]
513[[package]]
534−name = "oorandom"
514+name = "quick-error"
535−version = "11.1.0"
515+version = "1.2.2"
536source = "registry+https://github.com/rust-lang/crates.io-index"
516source = "registry+https://github.com/rust-lang/crates.io-index"
537
517
538[[package]]
518[[package]]
539−name = "pin-project"
519+name = "quote"
540−version = "0.4.16"
520+version = "0.6.11"
541source = "registry+https://github.com/rust-lang/crates.io-index"
521source = "registry+https://github.com/rust-lang/crates.io-index"
542dependencies = [
522dependencies = [
543− "pin-project-internal 0.4.16 (registry+https://github.com/rust-lang/crates.io-index)",
523+ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
544]
524]
545
525
546[[package]]
526[[package]]
547−name = "pin-project-internal"
527+name = "rand_core"
548−version = "0.4.16"
528+version = "0.3.1"
549source = "registry+https://github.com/rust-lang/crates.io-index"
529source = "registry+https://github.com/rust-lang/crates.io-index"
550dependencies = [
530dependencies = [
551− "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
552− "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
553− "syn 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)",
531+ "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
554]
532]
555
533
556[[package]]
534[[package]]
557−name = "pin-utils"
535+name = "rand_core"
558−version = "0.1.0"
536+version = "0.4.0"
559source = "registry+https://github.com/rust-lang/crates.io-index"
537source = "registry+https://github.com/rust-lang/crates.io-index"
560
538
561[[package]]
539[[package]]
562−name = "plotters"
540+name = "rand_os"
563−version = "0.2.12"
541+version = "0.1.3"
564source = "registry+https://github.com/rust-lang/crates.io-index"
542source = "registry+https://github.com/rust-lang/crates.io-index"
565dependencies = [
543dependencies = [
566− "js-sys 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)",
544+ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
545+ "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
567− "num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
546+ "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
568− "wasm-bindgen 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)",
547+ "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
548+ "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
569− "web-sys 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)",
549+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
570]
550]
571
551
572[[package]]
552[[package]]
573−name = "proc-macro-hack"
553+name = "rand_xoshiro"
574−version = "0.5.11"
554+version = "0.1.0"
575source = "registry+https://github.com/rust-lang/crates.io-index"
555source = "registry+https://github.com/rust-lang/crates.io-index"
576dependencies = [
556dependencies = [
577− "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
557+ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
578− "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
579− "syn 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)",
558+ "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
580]
559]
581
560
582[[package]]
561[[package]]
583−name = "proc-macro-nested"
562+name = "rayon"
584−version = "0.1.3"
563+version = "1.0.3"
585−source = "registry+https://github.com/rust-lang/crates.io-index"
586−
587−[[package]]
588−name = "proc-macro2"
589−version = "1.0.18"
590source = "registry+https://github.com/rust-lang/crates.io-index"
564source = "registry+https://github.com/rust-lang/crates.io-index"
591dependencies = [
565dependencies = [
592− "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
566+ "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
567+ "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
568+ "rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
593]
569]
594
570
595[[package]]
571[[package]]
596−name = "quote"
572+name = "rayon-core"
597−version = "1.0.2"
573+version = "1.4.1"
598source = "registry+https://github.com/rust-lang/crates.io-index"
574source = "registry+https://github.com/rust-lang/crates.io-index"
599dependencies = [
575dependencies = [
576+ "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
577+ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
578+ "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
600− "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
579+ "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
601]
580]
602
581
603[[package]]
582[[package]]
604−name = "rayon"
583+name = "rdrand"
605−version = "1.3.0"
584+version = "0.4.0"
606source = "registry+https://github.com/rust-lang/crates.io-index"
585source = "registry+https://github.com/rust-lang/crates.io-index"
607dependencies = [
586dependencies = [
608− "crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
609− "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
610− "rayon-core 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
587+ "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
611]
588]
612
589
613[[package]]
590[[package]]
614−name = "rayon-core"
591+name = "redox_syscall"
615−version = "1.7.0"
592+version = "0.1.52"
616source = "registry+https://github.com/rust-lang/crates.io-index"
593source = "registry+https://github.com/rust-lang/crates.io-index"
617−dependencies = [
618− "crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
619− "crossbeam-queue 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
620− "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
621− "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
622− "num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)",
623−]
624
594
625[[package]]
595[[package]]
626−name = "regex"
596+name = "redox_termios"
627−version = "1.3.3"
597+version = "0.1.1"
628source = "registry+https://github.com/rust-lang/crates.io-index"
598source = "registry+https://github.com/rust-lang/crates.io-index"
629dependencies = [
599dependencies = [
630− "regex-syntax 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
600+ "redox_syscall 0.1.52 (registry+https://github.com/rust-lang/crates.io-index)",
631]
601]
632
602
633[[package]]
603[[package]]
634−name = "regex-automata"
604+name = "regex"
635−version = "0.1.8"
605+version = "1.1.5"
636source = "registry+https://github.com/rust-lang/crates.io-index"
606source = "registry+https://github.com/rust-lang/crates.io-index"
637dependencies = [
607dependencies = [
608+ "aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
609+ "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
610+ "regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
611+ "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
638− "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
612+ "utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
639]
613]
640
614
641[[package]]
615[[package]]
642name = "regex-syntax"
616name = "regex-syntax"
643−version = "0.6.13"
617+version = "0.6.6"
644source = "registry+https://github.com/rust-lang/crates.io-index"
618source = "registry+https://github.com/rust-lang/crates.io-index"
619+dependencies = [
620+ "ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
621+]
645
622
646[[package]]
623[[package]]
647−name = "rustc_version"
624+name = "rustc-demangle"
648−version = "0.2.3"
625+version = "0.1.13"
649source = "registry+https://github.com/rust-lang/crates.io-index"
626source = "registry+https://github.com/rust-lang/crates.io-index"
650−dependencies = [
651− "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
652−]
653
627
654[[package]]
628[[package]]
655name = "ryu"
629name = "ryu"
656−version = "1.0.2"
630+version = "0.2.7"
657source = "registry+https://github.com/rust-lang/crates.io-index"
631source = "registry+https://github.com/rust-lang/crates.io-index"
658
632
659[[package]]
633[[package]]
660name = "same-file"
634name = "same-file"
661−version = "1.0.5"
635+version = "1.0.4"
662source = "registry+https://github.com/rust-lang/crates.io-index"
636source = "registry+https://github.com/rust-lang/crates.io-index"
663dependencies = [
637dependencies = [
664 "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
638 "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -671,109 +645,129 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
671
645
672[[package]]
646[[package]]
673name = "scopeguard"
647name = "scopeguard"
674−version = "1.0.0"
648+version = "0.3.3"
675source = "registry+https://github.com/rust-lang/crates.io-index"
649source = "registry+https://github.com/rust-lang/crates.io-index"
676
650
677[[package]]
651[[package]]
678−name = "semver"
652+name = "serde"
679−version = "0.9.0"
653+version = "1.0.90"
680source = "registry+https://github.com/rust-lang/crates.io-index"
654source = "registry+https://github.com/rust-lang/crates.io-index"
681dependencies = [
655dependencies = [
682− "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
656+ "serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
683]
657]
684
658
685[[package]]
659[[package]]
686−name = "semver-parser"
660+name = "serde_derive"
687−version = "0.7.0"
661+version = "1.0.90"
688source = "registry+https://github.com/rust-lang/crates.io-index"
662source = "registry+https://github.com/rust-lang/crates.io-index"
663+dependencies = [
664+ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
665+ "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
666+ "syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)",
667+]
689
668
690[[package]]
669[[package]]
691−name = "serde"
670+name = "serde_json"
692−version = "1.0.114"
671+version = "1.0.39"
693source = "registry+https://github.com/rust-lang/crates.io-index"
672source = "registry+https://github.com/rust-lang/crates.io-index"
694dependencies = [
673dependencies = [
674+ "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
675+ "ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
695− "serde_derive 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)",
676+ "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
696]
677]
697
678
698[[package]]
679[[package]]
699−name = "serde_cbor"
680+name = "sourcefile"
700−version = "0.11.1"
681+version = "0.1.4"
701source = "registry+https://github.com/rust-lang/crates.io-index"
682source = "registry+https://github.com/rust-lang/crates.io-index"
702−dependencies = [
703− "half 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
704− "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)",
705−]
706
683
707[[package]]
684[[package]]
708−name = "serde_derive"
685+name = "syn"
709−version = "1.0.114"
686+version = "0.15.30"
710source = "registry+https://github.com/rust-lang/crates.io-index"
687source = "registry+https://github.com/rust-lang/crates.io-index"
711dependencies = [
688dependencies = [
712− "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
689+ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
713− "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
690+ "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
714− "syn 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)",
691+ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
715]
692]
716
693
717[[package]]
694[[package]]
718−name = "serde_json"
695+name = "synstructure"
719−version = "1.0.57"
696+version = "0.10.1"
720source = "registry+https://github.com/rust-lang/crates.io-index"
697source = "registry+https://github.com/rust-lang/crates.io-index"
721dependencies = [
698dependencies = [
722− "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
699+ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
700+ "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
723− "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
701+ "syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)",
724− "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)",
702+ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
725]
703]
726
704
727[[package]]
705[[package]]
728−name = "slab"
706+name = "termcolor"
729−version = "0.4.2"
707+version = "1.0.4"
730source = "registry+https://github.com/rust-lang/crates.io-index"
708source = "registry+https://github.com/rust-lang/crates.io-index"
709+dependencies = [
710+ "wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
711+]
731
712
732[[package]]
713[[package]]
733−name = "sourcefile"
714+name = "termion"
734−version = "0.1.4"
715+version = "1.5.1"
735source = "registry+https://github.com/rust-lang/crates.io-index"
716source = "registry+https://github.com/rust-lang/crates.io-index"
717+dependencies = [
718+ "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
719+ "redox_syscall 0.1.52 (registry+https://github.com/rust-lang/crates.io-index)",
720+ "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
721+]
736
722
737[[package]]
723[[package]]
738−name = "syn"
724+name = "textwrap"
739−version = "1.0.33"
725+version = "0.10.0"
740source = "registry+https://github.com/rust-lang/crates.io-index"
726source = "registry+https://github.com/rust-lang/crates.io-index"
741dependencies = [
727dependencies = [
742− "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
743− "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
744− "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
728+ "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
745]
729]
746
730
747[[package]]
731[[package]]
748−name = "textwrap"
732+name = "thread_local"
749−version = "0.11.0"
733+version = "0.3.6"
750source = "registry+https://github.com/rust-lang/crates.io-index"
734source = "registry+https://github.com/rust-lang/crates.io-index"
751dependencies = [
735dependencies = [
752− "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
736+ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
753]
737]
754
738
755[[package]]
739[[package]]
756name = "tinytemplate"
740name = "tinytemplate"
757−version = "1.1.0"
741+version = "1.0.1"
758source = "registry+https://github.com/rust-lang/crates.io-index"
742source = "registry+https://github.com/rust-lang/crates.io-index"
759dependencies = [
743dependencies = [
760− "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)",
744+ "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
761− "serde_json 1.0.57 (registry+https://github.com/rust-lang/crates.io-index)",
745+ "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
762]
746]
763
747
748+[[package]]
749+name = "ucd-util"
750+version = "0.1.3"
751+source = "registry+https://github.com/rust-lang/crates.io-index"
752+
764[[package]]
753[[package]]
765name = "unicode-segmentation"
754name = "unicode-segmentation"
766−version = "1.6.0"
755+version = "1.2.1"
767source = "registry+https://github.com/rust-lang/crates.io-index"
756source = "registry+https://github.com/rust-lang/crates.io-index"
768
757
769[[package]]
758[[package]]
770name = "unicode-width"
759name = "unicode-width"
771−version = "0.1.6"
760+version = "0.1.5"
772source = "registry+https://github.com/rust-lang/crates.io-index"
761source = "registry+https://github.com/rust-lang/crates.io-index"
773
762
774[[package]]
763[[package]]
775name = "unicode-xid"
764name = "unicode-xid"
776−version = "0.2.0"
765+version = "0.1.0"
766+source = "registry+https://github.com/rust-lang/crates.io-index"
767+
768+[[package]]
769+name = "utf8-ranges"
770+version = "1.0.2"
777source = "registry+https://github.com/rust-lang/crates.io-index"
771source = "registry+https://github.com/rust-lang/crates.io-index"
778
772
779[[package]]
773[[package]]
@@ -783,126 +777,126 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
783
777
784[[package]]
778[[package]]
785name = "walkdir"
779name = "walkdir"
786−version = "2.3.1"
780+version = "2.2.7"
787source = "registry+https://github.com/rust-lang/crates.io-index"
781source = "registry+https://github.com/rust-lang/crates.io-index"
788dependencies = [
782dependencies = [
789− "same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
783+ "same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
790− "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
784+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
791 "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
785 "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
792]
786]
793
787
794[[package]]
788[[package]]
795name = "wasm-bindgen"
789name = "wasm-bindgen"
796−version = "0.2.55"
790+version = "0.2.42"
797source = "registry+https://github.com/rust-lang/crates.io-index"
791source = "registry+https://github.com/rust-lang/crates.io-index"
798dependencies = [
792dependencies = [
799− "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
800− "wasm-bindgen-macro 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)",
793+ "wasm-bindgen-macro 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
801]
794]
802
795
803[[package]]
796[[package]]
804name = "wasm-bindgen-backend"
797name = "wasm-bindgen-backend"
805−version = "0.2.55"
798+version = "0.2.42"
806source = "registry+https://github.com/rust-lang/crates.io-index"
799source = "registry+https://github.com/rust-lang/crates.io-index"
807dependencies = [
800dependencies = [
808− "bumpalo 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
801+ "bumpalo 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
809− "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
802+ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
810− "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
803+ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
811− "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
804+ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
812− "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
805+ "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
813− "syn 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)",
806+ "syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)",
814− "wasm-bindgen-shared 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)",
807+ "wasm-bindgen-shared 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
815]
808]
816
809
817[[package]]
810[[package]]
818name = "wasm-bindgen-futures"
811name = "wasm-bindgen-futures"
819−version = "0.4.5"
812+version = "0.3.19"
820source = "registry+https://github.com/rust-lang/crates.io-index"
813source = "registry+https://github.com/rust-lang/crates.io-index"
821dependencies = [
814dependencies = [
822− "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
815+ "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
823− "js-sys 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)",
816+ "js-sys 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
824− "wasm-bindgen 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)",
825− "web-sys 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)",
817+ "wasm-bindgen 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
826]
818]
827
819
828[[package]]
820[[package]]
829name = "wasm-bindgen-macro"
821name = "wasm-bindgen-macro"
830−version = "0.2.55"
822+version = "0.2.42"
831source = "registry+https://github.com/rust-lang/crates.io-index"
823source = "registry+https://github.com/rust-lang/crates.io-index"
832dependencies = [
824dependencies = [
833− "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
825+ "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
834− "wasm-bindgen-macro-support 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)",
826+ "wasm-bindgen-macro-support 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
835]
827]
836
828
837[[package]]
829[[package]]
838name = "wasm-bindgen-macro-support"
830name = "wasm-bindgen-macro-support"
839−version = "0.2.55"
831+version = "0.2.42"
840source = "registry+https://github.com/rust-lang/crates.io-index"
832source = "registry+https://github.com/rust-lang/crates.io-index"
841dependencies = [
833dependencies = [
842− "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
834+ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
843− "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
835+ "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
844− "syn 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)",
836+ "syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)",
845− "wasm-bindgen-backend 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)",
837+ "wasm-bindgen-backend 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
846− "wasm-bindgen-shared 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)",
838+ "wasm-bindgen-shared 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
847]
839]
848
840
849[[package]]
841[[package]]
850name = "wasm-bindgen-shared"
842name = "wasm-bindgen-shared"
851−version = "0.2.55"
843+version = "0.2.42"
852source = "registry+https://github.com/rust-lang/crates.io-index"
844source = "registry+https://github.com/rust-lang/crates.io-index"
853
845
854[[package]]
846[[package]]
855name = "wasm-bindgen-test"
847name = "wasm-bindgen-test"
856−version = "0.3.5"
848+version = "0.2.42"
857source = "registry+https://github.com/rust-lang/crates.io-index"
849source = "registry+https://github.com/rust-lang/crates.io-index"
858dependencies = [
850dependencies = [
859 "console_error_panic_hook 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
851 "console_error_panic_hook 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
852+ "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
860− "js-sys 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)",
853+ "js-sys 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
861 "scoped-tls 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
854 "scoped-tls 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
862− "wasm-bindgen 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)",
855+ "wasm-bindgen 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
863− "wasm-bindgen-futures 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
856+ "wasm-bindgen-futures 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
864− "wasm-bindgen-test-macro 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
857+ "wasm-bindgen-test-macro 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
865]
858]
866
859
867[[package]]
860[[package]]
868name = "wasm-bindgen-test-macro"
861name = "wasm-bindgen-test-macro"
869−version = "0.3.5"
862+version = "0.2.42"
870source = "registry+https://github.com/rust-lang/crates.io-index"
863source = "registry+https://github.com/rust-lang/crates.io-index"
871dependencies = [
864dependencies = [
872− "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
865+ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
873− "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
866+ "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
874]
867]
875
868
876[[package]]
869[[package]]
877name = "wasm-bindgen-webidl"
870name = "wasm-bindgen-webidl"
878−version = "0.2.55"
871+version = "0.2.42"
879source = "registry+https://github.com/rust-lang/crates.io-index"
872source = "registry+https://github.com/rust-lang/crates.io-index"
880dependencies = [
873dependencies = [
881− "anyhow 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
874+ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
882 "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
875 "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
883− "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
876+ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
884− "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
877+ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
885− "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
878+ "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
886− "syn 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)",
879+ "syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)",
887− "wasm-bindgen-backend 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)",
880+ "wasm-bindgen-backend 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
888− "weedle 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
881+ "weedle 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
889]
882]
890
883
891[[package]]
884[[package]]
892name = "web-sys"
885name = "web-sys"
893−version = "0.3.32"
886+version = "0.3.19"
894source = "registry+https://github.com/rust-lang/crates.io-index"
887source = "registry+https://github.com/rust-lang/crates.io-index"
895dependencies = [
888dependencies = [
889+ "env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
896− "anyhow 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
890+ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
897− "js-sys 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)",
891+ "js-sys 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
898 "sourcefile 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
892 "sourcefile 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
899− "wasm-bindgen 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)",
893+ "wasm-bindgen 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
900− "wasm-bindgen-webidl 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)",
894+ "wasm-bindgen-webidl 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
901]
895]
902
896
903[[package]]
897[[package]]
904name = "weedle"
898name = "weedle"
905−version = "0.10.0"
899+version = "0.8.0"
906source = "registry+https://github.com/rust-lang/crates.io-index"
900source = "registry+https://github.com/rust-lang/crates.io-index"
907dependencies = [
901dependencies = [
908 "nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
902 "nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -910,7 +904,7 @@ dependencies = [
910
904
911[[package]]
905[[package]]
912name = "winapi"
906name = "winapi"
913−version = "0.3.8"
907+version = "0.3.7"
914source = "registry+https://github.com/rust-lang/crates.io-index"
908source = "registry+https://github.com/rust-lang/crates.io-index"
915dependencies = [
909dependencies = [
916 "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
910 "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -927,7 +921,7 @@ name = "winapi-util"
927version = "0.1.2"
921version = "0.1.2"
928source = "registry+https://github.com/rust-lang/crates.io-index"
922source = "registry+https://github.com/rust-lang/crates.io-index"
929dependencies = [
923dependencies = [
930− "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
924+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
931]
925]
932
926
933[[package]]
927[[package]]
@@ -935,101 +929,111 @@ name = "winapi-x86_64-pc-windows-gnu"
935version = "0.4.0"
929version = "0.4.0"
936source = "registry+https://github.com/rust-lang/crates.io-index"
930source = "registry+https://github.com/rust-lang/crates.io-index"
937
931
932+[[package]]
933+name = "wincolor"
934+version = "1.0.1"
935+source = "registry+https://github.com/rust-lang/crates.io-index"
936+dependencies = [
937+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
938+ "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
939+]
940+
938[metadata]
941[metadata]
939−"checksum anyhow 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "9267dff192e68f3399525901e709a48c1d3982c9c072fa32f2127a0cb0babf14"
942+"checksum aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e6f484ae0c99fec2e858eb6134949117399f222608d84cadb3f58c1f97c2364c"
943+"checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71"
940−"checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90"
944+"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
941−"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
945+"checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799"
942−"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
946+"checksum backtrace 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "f106c02a3604afcdc0df5d36cc47b44b55917dbaf3d808f71c163a0ddba64637"
943−"checksum bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8d6c2c5b58ab920a4f5aeaaca34b4488074e8cc7596af94e6f8c6ff247c60245"
947+"checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6"
948+"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
944−"checksum bumpalo 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad807f2fc2bf185eeb98ff3a901bd46dc5ad58163d0fa4577ba0d25674d71708"
949+"checksum bumpalo 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4639720be048090544634e0402490838995ccdc9d2fe648f528f30d3c33ae71f"
945−"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
950+"checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb"
946−"checksum cast 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4b9434b9a5aa1450faa3f9cb14ea0e8c53bb5d2b3c1bfd1ab4fc03e9f33fbfb0"
951+"checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427"
952+"checksum cc 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)" = "30f813bf45048a18eda9190fd3c6b78644146056740c43172a5a3699118588fd"
947−"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
953+"checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4"
948−"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
954+"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e"
955+"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
949"checksum console_error_panic_hook 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d976903543e0c48546a91908f21588a680a8c8f984df9a5d69feccb2b2a211"
956"checksum console_error_panic_hook 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d976903543e0c48546a91908f21588a680a8c8f984df9a5d69feccb2b2a211"
950−"checksum console_log 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "501a375961cef1a0d44767200e66e4a559283097e91d0730b1d75dfb2f8a1494"
957+"checksum console_log 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1e7871d2947441b0fdd8e2bd1ce2a2f75304f896582c0d572162d48290683c48"
951−"checksum criterion 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "70daa7ceec6cf143990669a04c7df13391d55fb27bd4079d252fca774ba244d8"
958+"checksum criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0363053954f3e679645fc443321ca128b7b950a6fe288cf5f9335cc22ee58394"
952−"checksum criterion-plot 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e022feadec601fba1649cfa83586381a4ad31c6bf3a9ab7d408118b05dd9889d"
959+"checksum criterion-plot 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76f9212ddf2f4a9eb2d401635190600656a1f88a932ef53d06e7fa4c7e02fb8e"
953−"checksum crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3aa945d63861bfe624b55d153a39684da1e8c0bc8fba932f7ee3a3c16cea3ca"
960+"checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3"
954−"checksum crossbeam-epoch 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5064ebdbf05ce3cb95e45c8b086f72263f4166b29b97f6baff7ef7fe047b55ac"
961+"checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150"
955−"checksum crossbeam-queue 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dfd6515864a82d2f877b42813d4553292c6659498c9a2aa31bab5a15243c2700"
956−"checksum crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce446db02cdc3165b94ae73111e570793400d0794e46125cc4056c81cbb039f4"
962+"checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9"
957−"checksum csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37519ccdfd73a75821cac9319d4fce15a81b9fcf75f951df5b9988aa3a0af87d"
963+"checksum csv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "9fd1c44c58078cfbeaf11fbb3eac9ae5534c23004ed770cc4bfb48e658ae4f04"
958−"checksum csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9b5cadb6b25c77aeff80ba701712494213f4a8418fcda2ee11b6560c3ad0bf4c"
964+"checksum csv-core 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa5cdef62f37e6ffe7d1f07a381bc0db32b7a3ff1cac0de56cb0d81e71f53d65"
959−"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
965+"checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b"
960−"checksum futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1e05b85ec287aac0dc34db7d4a569323df697f9c55b99b15d6b4ef8cde49f613"
966+"checksum env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b61fa891024a945da30a9581546e8cfaf5602c7b3f4c137a2805cf388f92075a"
961−"checksum futures-channel 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f366ad74c28cca6ba456d95e6422883cfb4b252a83bed929c83abfdbbf2967d5"
962−"checksum futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "59f5fff90fd5d971f936ad674802482ba441b6f09ba5e15fd8b39145582ca399"
967+"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2"
963−"checksum futures-executor 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "10d6bb888be1153d3abeb9006b11b02cf5e9b209fda28693c31ae1e4e012e314"
968+"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1"
964−"checksum futures-io 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "de27142b013a8e869c14957e6d2edeef89e97c289e69d042ee3a49acd8b51789"
969+"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
965−"checksum futures-macro 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d0b5a30a4328ab5473878237c447333c093297bded83a4983d10f4deea240d39"
970+"checksum futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" = "62941eff9507c8177d448bd83a44d9b9760856e184081d8cd79ba9f03dd24981"
966−"checksum futures-sink 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3f2032893cb734c7a05d85ce0cc8b8c4075278e93b24b66f9de99d6eb0fa8acc"
967−"checksum futures-task 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "bdb66b5f09e22019b1ab0830f7785bcea8e7a42148683f99214f73f8ec21a626"
968−"checksum futures-util 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8764574ff08b701a084482c3c7031349104b07ac897393010494beaa18ce32c6"
969"checksum fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
971"checksum fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
970−"checksum half 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d36fab90f82edc3c747f9d438e06cf0a491055896f2a279638bb5beed6c40177"
971"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
972"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
972−"checksum hermit-abi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "307c3c9f937f38e3534b1d6447ecf090cafcc9744e4a6360e8b037b2cf5af120"
973+"checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114"
973−"checksum itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b"
974+"checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358"
974−"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
975+"checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b"
975−"checksum js-sys 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)" = "1c840fdb2167497b0bd0db43d6dfe61e91637fa72f9d061f8bd17ddc44ba6414"
976+"checksum js-sys 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "3c994fd445b81741d77f6bcd227d6ed645b95b35a2ecfd2050767450ff1c0b6d"
976−"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
977+"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14"
977−"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558"
978+"checksum libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)" = "bedcc7a809076656486ffe045abeeac163da1b558e963a31e29fbfbeba916917"
978−"checksum log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
979+"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
979"checksum longest-increasing-subsequence 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b3bd0dd2cd90571056fdb71f6275fada10131182f84899f4b2a916e565d81d86"
980"checksum longest-increasing-subsequence 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b3bd0dd2cd90571056fdb71f6275fada10131182f84899f4b2a916e565d81d86"
980−"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e"
981+"checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39"
981−"checksum memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "75189eb85871ea5c2e2c15abbdd541185f63b408415e5051f5cac122d8c774b9"
982+"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
983+"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
982"checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6"
984"checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6"
983−"checksum num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c81ffc11c212fa327657cb19dd85eb7419e163b5b076bede2bdb5c974c07e4"
985+"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1"
984−"checksum num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76dac5ed2a876980778b8b85f75a71b6cbf0db0b1232ee12f826bccb00d09d72"
986+"checksum num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a23f0ed30a54abaa0c7e83b1d2d87ada7c3c23078d1d87815af3e3b6385fbba"
985−"checksum once_cell 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b1c601810575c99596d4afc46f78a678c80105117c379eb3650cf99b8a21ce5b"
987+"checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915"
986−"checksum oorandom 11.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ebcec7c9c2a95cacc7cd0ecb89d8a8454eca13906f6deb55258ffff0adeb9405"
988+"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
987−"checksum pin-project 0.4.16 (registry+https://github.com/rust-lang/crates.io-index)" = "81d480cb4e89522ccda96d0eed9af94180b7a5f93fb28f66e1fd7d68431663d1"
989+"checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1"
988−"checksum pin-project-internal 0.4.16 (registry+https://github.com/rust-lang/crates.io-index)" = "a82996f11efccb19b685b14b5df818de31c1edcee3daa256ab5775dd98e72feb"
990+"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
989−"checksum pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
991+"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0"
990−"checksum plotters 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "4e3bb8da247d27ae212529352020f3e5ee16e83c0c258061d27b08ab92675eeb"
992+"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
991−"checksum proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)" = "ecd45702f76d6d3c75a80564378ae228a85f0b59d2f3ed43c91b4a69eb2ebfc5"
993+"checksum rand_xoshiro 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "03b418169fb9c46533f326efd6eed2576699c44ca92d3052a066214a8d828929"
992−"checksum proc-macro-nested 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "369a6ed065f249a159e06c45752c780bda2fb53c995718f9e484d08daa9eb42e"
994+"checksum rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "373814f27745b2686b350dd261bfd24576a6fb0e2c5919b3a2b6005f820b0473"
993−"checksum proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "beae6331a816b1f65d04c45b078fd8e6c93e8071771f41b8163255bbd8d7c8fa"
995+"checksum rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b055d1e92aba6877574d8fe604a63c8b5df60f60e5982bf7ccbb1338ea527356"
994−"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
996+"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
995−"checksum rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "db6ce3297f9c85e16621bb8cca38a06779ffc31bb8184e1be4bed2be4678a098"
997+"checksum redox_syscall 0.1.52 (registry+https://github.com/rust-lang/crates.io-index)" = "d32b3053e5ced86e4bc0411fec997389532bf56b000e66cb4884eeeb41413d69"
996−"checksum rayon-core 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "08a89b46efaf957e52b18062fb2f4660f8b8a4dde1807ca002690868ef2c85a9"
998+"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
997−"checksum regex 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b5508c1941e4e7cb19965abef075d35a9a8b5cdf0846f30b4050e9b55dc55e87"
998−"checksum regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "92b73c2a1770c255c240eaa4ee600df1704a38dc3feaa6e949e7fcd4f8dc09f9"
999+"checksum regex 1.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "559008764a17de49a3146b234641644ed37d118d1ef641a0bb573d146edc6ce0"
999−"checksum regex-syntax 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e734e891f5b408a29efbf8309e656876276f49ab6a6ac208600b4419bd893d90"
1000+"checksum regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dcfd8681eebe297b81d98498869d4aae052137651ad7b96822f09ceb690d0a96"
1000−"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
1001+"checksum rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "adacaae16d02b6ec37fdc7acfcddf365978de76d1983d3ee22afc260e1ca9619"
1001−"checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8"
1002+"checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7"
1002−"checksum same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "585e8ddcedc187886a30fa705c47985c3fa88d06624095856b36ca0b82ff4421"
1003+"checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267"
1003"checksum scoped-tls 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
1004"checksum scoped-tls 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
1004−"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d"
1005+"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
1005−"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
1006−"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
1007−"checksum serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)" = "5317f7588f0a5078ee60ef675ef96735a1442132dc645eb1d12c018620ed8cd3"
1006+"checksum serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)" = "aa5f7c20820475babd2c077c3ab5f8c77a31c15e16ea38687b4c02d3e48680f4"
1008−"checksum serde_cbor 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1e18acfa2f90e8b735b2836ab8d538de304cbb6729a7360729ea5a895d15a622"
1009−"checksum serde_derive 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)" = "2a0be94b04690fbaed37cddffc5c134bf537c8e3329d53e982fe04c374978f8e"
1007+"checksum serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)" = "58fc82bec244f168b23d1963b45c8bf5726e9a15a9d146a067f9081aeed2de79"
1010−"checksum serde_json 1.0.57 (registry+https://github.com/rust-lang/crates.io-index)" = "164eacbdb13512ec2745fb09d51fd5b22b0d65ed294a1dcf7285a360c80a675c"
1008+"checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d"
1011−"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
1012"checksum sourcefile 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4bf77cb82ba8453b42b6ae1d692e4cdc92f9a47beaf89a847c8be83f4e328ad3"
1009"checksum sourcefile 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4bf77cb82ba8453b42b6ae1d692e4cdc92f9a47beaf89a847c8be83f4e328ad3"
1013−"checksum syn 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)" = "e8d5d96e8cbb005d6959f119f773bfaebb5684296108fb32600c00cde305b2cd"
1010+"checksum syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)" = "66c8865bf5a7cbb662d8b011950060b3c8743dca141b054bf7195b20d314d8e2"
1014−"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
1011+"checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015"
1015−"checksum tinytemplate 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d3dc76004a03cec1c5932bca4cdc2e39aaa798e3f82363dd94f9adf6098c12f"
1012+"checksum termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f"
1013+"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
1014+"checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6"
1015+"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
1016+"checksum tinytemplate 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7655088894274afb52b807bd3c87072daa1fedd155068b8705cabfd628956115"
1017+"checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86"
1016−"checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
1018+"checksum unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aa6024fc12ddfd1c6dbc14a80fa2324d4568849869b779f6bd37e5e4c03344d1"
1017−"checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20"
1019+"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
1018−"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
1020+"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
1021+"checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737"
1019"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
1022"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
1020−"checksum walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d"
1023+"checksum walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d9d7ed3431229a144296213105a390676cc49c9b6a72bd19f3176c98e129fa1"
1021−"checksum wasm-bindgen 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)" = "29ae32af33bacd663a9a28241abecf01f2be64e6a185c6139b04f18b6385c5f2"
1024+"checksum wasm-bindgen 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)" = "ffde3534e5fa6fd936e3260cd62cd644b8656320e369388f9303c955895e35d4"
1022−"checksum wasm-bindgen-backend 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)" = "1845584bd3593442dc0de6e6d9f84454a59a057722f36f005e44665d6ab19d85"
1025+"checksum wasm-bindgen-backend 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)" = "40c0543374a7ae881cdc5d32d19de28d1d1929e92263ffa7e31712cc2d53f9f1"
1023−"checksum wasm-bindgen-futures 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1458706aa1b8fe6898d19433c9f110d93a05d1f22ae6adf55810409a94df34b4"
1026+"checksum wasm-bindgen-futures 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "0ad171fc1f6e43f97d155d27f4ee5657bd8aa5cce7c497ef3a0a0c5b44618b2d"
1024−"checksum wasm-bindgen-macro 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)" = "87fcc747e6b73c93d22c947a6334644d22cfec5abd8b66238484dc2b0aeb9fe4"
1027+"checksum wasm-bindgen-macro 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)" = "f914c94c2c5f4c9364510ca2429e59c92157ec89429243bcc245e983db990a71"
1025−"checksum wasm-bindgen-macro-support 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)" = "3dc4b3f2c4078c8c4a5f363b92fcf62604c5913cbd16c6ff5aaf0f74ec03f570"
1028+"checksum wasm-bindgen-macro-support 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)" = "9168c413491e4233db7b6884f09a43beb00c14d11d947ffd165242daa48a2385"
1026−"checksum wasm-bindgen-shared 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)" = "ca0b78d6d3be8589b95d1d49cdc0794728ca734adf36d7c9f07e6459508bb53d"
1029+"checksum wasm-bindgen-shared 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)" = "326c32126e1a157b6ced7400061a84ac5b11182b2cda6edad7314eb3ae9ac9fe"
1027−"checksum wasm-bindgen-test 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ed5833682054e941db0b7e2b4877b61bbaafd680608e40d268e070d34558b305"
1030+"checksum wasm-bindgen-test 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)" = "8aed4ef1aa56f2ef4aff593c516de6a3e48711c703b3f7415c9151a7c9babd17"
1028−"checksum wasm-bindgen-test-macro 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "9c5dcf70d21d0ff0ea5cdb97dba9a9b56ddad4a9bd10c8912eedc55618be022f"
1031+"checksum wasm-bindgen-test-macro 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)" = "eb477c50f3c9a9ecd99c78fb9bd3b6599d414b918d5f72165b12c53738011ae1"
1029−"checksum wasm-bindgen-webidl 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)" = "3126356474ceb717c8fb5549ae387c9fbf4872818454f4d87708bee997214bb5"
1032+"checksum wasm-bindgen-webidl 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)" = "613dbf4d7d3bf10aeb212b35de14a8ef07222c26526d4f931061a83fc9e2a851"
1030−"checksum web-sys 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)" = "98405c0a2e722ed3db341b4c5b70eb9fe0021621f7350bab76df93b09b649bbf"
1033+"checksum web-sys 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "24129e4be2281109b3e15a328d3d7f233ee232a5405f75ba1e9bb59a25ebc4d4"
1031−"checksum weedle 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3bb43f70885151e629e2a19ce9e50bd730fd436cfd4b666894c9ce4de9141164"
1034+"checksum weedle 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "26a4c67f132386d965390b8a734d5d10adbcd30eb5cc74bd9229af8b83f10044"
1032−"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
1035+"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770"
1033"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
1036"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
1034"checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9"
1037"checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9"
1035"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
1038"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
1039+"checksum wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "561ed901ae465d6185fa7864d63fbd5720d0ef718366c9a4dc83cf6170d7e9ba"
Cargo.toml+16−24
@@ -8,7 +8,7 @@ license = "MPL-2.0"
8name = "dodrio"
8name = "dodrio"
9readme = "./README.md"
9readme = "./README.md"
10repository = "https://github.com/fitzgen/dodrio"
10repository = "https://github.com/fitzgen/dodrio"
11−version = "0.2.0"
11+version = "0.1.0"
12
12
13[badges]
13[badges]
14travis-ci = { repository = "fitzgen/dodrio" }
14travis-ci = { repository = "fitzgen/dodrio" }
@@ -29,31 +29,24 @@ harness = false
29required-features = ["xxx-unstable-internal-use-only"]
29required-features = ["xxx-unstable-internal-use-only"]
30
30
31[features]
31[features]
32−# Don't rely on this feature! Its behavior will change and it could go away at
33−# any time. This enables monkey-patching DOM methods so that we wrap them and
34−# trace what DOM methods are used and how many times they are invoked when
35−# applying our emitted change lists to the physical DOM. This is useful for
36−# evaluating the differences between how Dodrio applies changes from virtual
37−# nodes to the physical DOM versus how other virtual DOM libraries do the same.
38−xxx-unstable-strace = []
39−
40# Don't use this feature! It only exists for exposing otherwise-internal APIs
32# Don't use this feature! It only exists for exposing otherwise-internal APIs
41# for testing and benchmarks.
33# for testing and benchmarks.
42xxx-unstable-internal-use-only = []
34xxx-unstable-internal-use-only = []
43
35
44[dependencies]
36[dependencies]
45−bumpalo = "2.6.0"
37+bumpalo = "2.4.1"
46−cfg-if = "0.1.10"
38+cfg-if = "0.1.7"
39+futures = "0.1.26"
40+wasm-bindgen = "0.2.42"
41+wasm-bindgen-futures = "0.3.19"
42+js-sys = "0.3.19"
47fxhash = "0.2.1"
43fxhash = "0.2.1"
48−js-sys = "0.3.32"
49−log = { version = "0.4.11", optional = true }
44+log = { version = "0.4.6", optional = true }
45+bitflags = "1.0.4"
50longest-increasing-subsequence = "0.1.0"
46longest-increasing-subsequence = "0.1.0"
51−serde = { version = "1.0.114", optional = true }
52−wasm-bindgen = "0.2.55"
53−wasm-bindgen-futures = "0.4.5"
54
47
55[dependencies.web-sys]
48[dependencies.web-sys]
56−version = "0.3.32"
49+version = "0.3.19"
57features = [
50features = [
58 "console",
51 "console",
59 "Document",
52 "Document",
@@ -64,14 +57,13 @@ features = [
64]
57]
65
58
66[dev-dependencies]
59[dev-dependencies]
67−console_log = "0.2.0"
60+console_log = "0.1.2"
68−dodrio-js-api = { version = "=0.2.0", path = "./crates/js-api" }
61+dodrio-js-api = { version = "=0.1.0", path = "./crates/js-api" }
69−futures = "0.3.5"
70−log = "0.4.11"
62+log = "0.4.6"
71−wasm-bindgen-test = "0.3.5"
63+wasm-bindgen-test = "0.2.42"
72
64
73[dev-dependencies.web-sys]
65[dev-dependencies.web-sys]
74−version = "0.3.32"
66+version = "0.3.19"
75features = [
67features = [
76 "Attr",
68 "Attr",
77 "EventTarget",
69 "EventTarget",
@@ -81,7 +73,7 @@ features = [
81]
73]
82
74
83[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies]
75[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies]
84−criterion = "0.3.3"
76+criterion = "0.2.11"
85
77
86[profile.bench]
78[profile.bench]
87debug = true
79debug = true
README.md−9
@@ -57,15 +57,6 @@ directory](https://github.com/fitzgen/dodrio/tree/master/examples), including:
57* [`js-component`](https://github.com/fitzgen/dodrio/tree/master/examples/js-component):
57* [`js-component`](https://github.com/fitzgen/dodrio/tree/master/examples/js-component):
58 Defines a rendering component in JavaScript with the `dodrio-js-api` crate.
58 Defines a rendering component in JavaScript with the `dodrio-js-api` crate.
59
59
60−## Cargo Features
61−
62−* `log` — enable debugging-oriented log messages with the `log` crate's
63− facade. You still have to initialize a logger for the messages to go anywhere,
64− such as [`console_log`](https://github.com/iamcodemaker/console_log).
65−
66−* `serde` — enable `serde::{Serialize, Deserialize}` implementations for
67− `Cached<R>` where `R` is serializable and deserializable.
68−
69## Design
60## Design
70
61
71### Bump Allocation
62### Bump Allocation
benches/benches.rs+24−13
@@ -13,20 +13,19 @@ use dodrio::{
13 CachedSet, Node, Render, RenderContext, Vdom,
13 CachedSet, Node, Render, RenderContext, Vdom,
14};
14};
15use std::cell::RefCell;
15use std::cell::RefCell;
16−use std::convert::TryInto;
17
16
18/// The simplest thing we can render: `<div/>`.
17/// The simplest thing we can render: `<div/>`.
19struct Empty;
18struct Empty;
20−impl<'a> Render<'a> for Empty {
19+impl Render for Empty {
21− fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
20+ fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
22 div(&cx).finish()
21 div(&cx).finish()
23 }
22 }
24}
23}
25
24
26/// Render a list that is `self.0` items long, has attributes and listeners.
25/// Render a list that is `self.0` items long, has attributes and listeners.
27struct SimpleList(usize);
26struct SimpleList(usize);
28−impl<'a> Render<'a> for SimpleList {
27+impl Render for SimpleList {
29− fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
28+ fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
30 let mut children = bumpalo::collections::Vec::with_capacity_in(self.0, cx.bump);
29 let mut children = bumpalo::collections::Vec::with_capacity_in(self.0, cx.bump);
31 children.extend((0..self.0).map(|_| {
30 children.extend((0..self.0).map(|_| {
32 li(&cx)
31 li(&cx)
@@ -47,10 +46,9 @@ fn criterion_benchmark(c: &mut Criterion) {
47 Benchmark::new("empty", {
46 Benchmark::new("empty", {
48 let mut bump = Bump::new();
47 let mut bump = Bump::new();
49 let cached_set = RefCell::new(CachedSet::default());
48 let cached_set = RefCell::new(CachedSet::default());
50− let mut templates = Default::default();
51 move |b| {
49 move |b| {
52 bump.reset();
50 bump.reset();
53− let mut cx = RenderContext::new(&bump, &cached_set, &mut templates);
51+ let mut cx = RenderContext::new(&bump, &cached_set);
54 b.iter(|| {
52 b.iter(|| {
55 black_box(Empty.render(&mut cx));
53 black_box(Empty.render(&mut cx));
56 })
54 })
@@ -65,18 +63,24 @@ fn criterion_benchmark(c: &mut Criterion) {
65 {
63 {
66 let mut bump = Bump::new();
64 let mut bump = Bump::new();
67 let cached_set = RefCell::new(CachedSet::default());
65 let cached_set = RefCell::new(CachedSet::default());
68− let mut templates = Default::default();
69 move |b, n| {
66 move |b, n| {
70 bump.reset();
67 bump.reset();
71− let mut cx = RenderContext::new(&bump, &cached_set, &mut templates);
68+ let mut cx = RenderContext::new(&bump, &cached_set);
72 b.iter(|| {
69 b.iter(|| {
73 black_box(SimpleList(*n).render(&mut cx));
70 black_box(SimpleList(*n).render(&mut cx));
74 })
71 })
75 }
72 }
76 },
73 },
74+ vec![
75+ // TODO: Only test one `n` value until
76+ // https://github.com/bheisler/criterion.rs/issues/269 is fixed.
77+ //
78+ // 100,
79+ // 1_000,
77− vec![100, 1_000, 10_000],
80+ 10_000,
81+ ],
78 )
82 )
79− .throughput(|n| Throughput::Elements((*n).try_into().unwrap())),
83+ .throughput(|n| Throughput::Elements(*n as u32)),
80 );
84 );
81
85
82 c.bench(
86 c.bench(
@@ -90,7 +94,14 @@ fn criterion_benchmark(c: &mut Criterion) {
90 black_box(&vdom);
94 black_box(&vdom);
91 })
95 })
92 },
96 },
97+ vec![
98+ // TODO: Only test one `n` value until
99+ // https://github.com/bheisler/criterion.rs/issues/269 is fixed.
100+ //
101+ // 100,
102+ // 1_000,
93− vec![100, 1_000, 10_000],
103+ 10_000,
104+ ],
94 )
105 )
95 .with_function("empty-to-full-list-to-empty", |b, &n| {
106 .with_function("empty-to-full-list-to-empty", |b, &n| {
96 b.iter(|| {
107 b.iter(|| {
@@ -110,7 +121,7 @@ fn criterion_benchmark(c: &mut Criterion) {
110 black_box(&vdom);
121 black_box(&vdom);
111 })
122 })
112 })
123 })
113− .throughput(|n| Throughput::Elements((*n).try_into().unwrap())),
124+ .throughput(|n| Throughput::Elements(*n as u32)),
114 );
125 );
115}
126}
116
127
crates/js-api/Cargo.toml+7−6
@@ -7,16 +7,17 @@ keywords = ["javascript", "js", "vdom", "virtual-dom"]
7license = "MPL-2.0"
7license = "MPL-2.0"
8name = "dodrio-js-api"
8name = "dodrio-js-api"
9repository = "https://github.com/fitzgen/dodrio"
9repository = "https://github.com/fitzgen/dodrio"
10−version = "0.2.0"
10+version = "0.1.0"
11
11
12[badges]
12[badges]
13travis-ci = { repository = "fitzgen/dodrio" }
13travis-ci = { repository = "fitzgen/dodrio" }
14
14
15[dependencies]
15[dependencies]
16−dodrio = { version = "=0.2.0", path = "../.." }
16+dodrio = { version = "=0.1.0", path = "../.." }
17−wasm-bindgen = "0.2.55"
17+wasm-bindgen = "0.2.42"
18−js-sys = "0.3.32"
18+js-sys = "0.3.19"
19−wasm-bindgen-futures = "0.4.5"
19+wasm-bindgen-futures = "0.3.19"
20+futures = "0.1.26"
20
21
21[dev-dependencies]
22[dev-dependencies]
22−wasm-bindgen-test = "0.3.5"
23+wasm-bindgen-test = "0.2.42"
crates/js-api/src/lib.rs+10−13
@@ -99,8 +99,8 @@ impl GreetingViaJs {
99
99
100/// And finally the `Render` implementation! This adds a `<p>` element and some
100/// And finally the `Render` implementation! This adds a `<p>` element and some
101/// text around whatever the inner JS `Greeting` component renders.
101/// text around whatever the inner JS `Greeting` component renders.
102−impl<'a> Render<'a> for GreetingViaJs {
102+impl Render for GreetingViaJs {
103− fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
103+ fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
104 use dodrio::builder::*;
104 use dodrio::builder::*;
105 p(&cx)
105 p(&cx)
106 .children([
106 .children([
@@ -116,6 +116,7 @@ impl<'a> Render<'a> for GreetingViaJs {
116#![deny(missing_docs, missing_debug_implementations)]
116#![deny(missing_docs, missing_debug_implementations)]
117
117
118use dodrio::{builder, bumpalo, Node, Render, RenderContext};
118use dodrio::{builder, bumpalo, Node, Render, RenderContext};
119+use futures::prelude::*;
119use js_sys::{Object, Promise, Reflect};
120use js_sys::{Object, Promise, Reflect};
120use wasm_bindgen::prelude::*;
121use wasm_bindgen::prelude::*;
121use wasm_bindgen::JsCast;
122use wasm_bindgen::JsCast;
@@ -184,16 +185,12 @@ impl VdomWeak {
184 /// Schedule re-rendering of the virtual DOM. A promise is returned that is
185 /// Schedule re-rendering of the virtual DOM. A promise is returned that is
185 /// resolved after the rendering has happened.
186 /// resolved after the rendering has happened.
186 pub fn render(&self) -> Promise {
187 pub fn render(&self) -> Promise {
187− let future = self.inner.render();
188−
189− wasm_bindgen_futures::future_to_promise(async move {
188+ wasm_bindgen_futures::future_to_promise(
190− if let Err(e) = future.await {
189+ self.inner.render().map(|_| JsValue::null()).map_err(|e| {
191 let msg = e.to_string();
190 let msg = e.to_string();
192− Err(js_sys::Error::new(&msg).into())
191+ js_sys::Error::new(&msg).into()
193− } else {
192+ }),
194− Ok(JsValue::null())
195− }
196− })
193+ )
197 }
194 }
198}
195}
199
196
@@ -216,8 +213,8 @@ impl JsRender {
216 }
213 }
217}
214}
218
215
219−impl<'a> Render<'a> for JsRender {
216+impl Render for JsRender {
220− fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
217+ fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
221 create(cx, self.render())
218 create(cx, self.render())
222 }
219 }
223}
220}
examples/counter/Cargo.toml+5−5
@@ -11,13 +11,13 @@ crate-type = ["cdylib"]
11
11
12[dependencies]
12[dependencies]
13console_error_panic_hook = "0.1.6"
13console_error_panic_hook = "0.1.6"
14−console_log = "0.2.0"
14+console_log = "0.1.2"
15dodrio = { path = "../.." }
15dodrio = { path = "../.." }
16−log = "0.4.11"
16+log = "0.4.6"
17−wasm-bindgen = "0.2.55"
17+wasm-bindgen = "0.2.42"
18
18
19[dependencies.web-sys]
19[dependencies.web-sys]
20−version = "0.3.32"
20+version = "0.3.19"
21features = [
21features = [
22 "console",
22 "console",
23 "Document",
23 "Document",
@@ -30,4 +30,4 @@ features = [
30]
30]
31
31
32[dev-dependencies]
32[dev-dependencies]
33−wasm-bindgen-test = "0.3.5"
33+wasm-bindgen-test = "0.2.42"
examples/counter/src/lib.rsmode 100755 → 100644+4−5
@@ -1,4 +1,4 @@
1−use dodrio::{bumpalo, Node, Render, RenderContext};
1+use dodrio::{bumpalo, Render, RenderContext};
2use log::*;
2use log::*;
3use wasm_bindgen::prelude::*;
3use wasm_bindgen::prelude::*;
4
4
@@ -26,8 +26,8 @@ impl Counter {
26
26
27// The `Render` implementation for `Counter`s displays the current count and has
27// The `Render` implementation for `Counter`s displays the current count and has
28// buttons to increment and decrement the count.
28// buttons to increment and decrement the count.
29−impl<'a> Render<'a> for Counter {
29+impl Render for Counter {
30− fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
30+ fn render<'a>(&self, cx: &mut RenderContext<'a>) -> dodrio::Node<'a> {
31 use dodrio::builder::*;
31 use dodrio::builder::*;
32
32
33 // Stringify the count as a bump-allocated string.
33 // Stringify the count as a bump-allocated string.
@@ -54,8 +54,7 @@ impl<'a> Render<'a> for Counter {
54 button(&cx)
54 button(&cx)
55 .on("click", |root, vdom, _event| {
55 .on("click", |root, vdom, _event| {
56 // Same as above, but decrementing instead of incrementing.
56 // Same as above, but decrementing instead of incrementing.
57− let counter = root.unwrap_mut::<Counter>();
57+ root.unwrap_mut::<Counter>().decrement();
58− counter.decrement();
59 vdom.schedule_render();
58 vdom.schedule_render();
60 })
59 })
61 .children([text("-")])
60 .children([text("-")])
examples/game-of-life/Cargo.toml+6−5
@@ -11,13 +11,14 @@ crate-type = ["cdylib"]
11
11
12[dependencies]
12[dependencies]
13dodrio = { path = "../.." }
13dodrio = { path = "../.." }
14−wasm-bindgen = "0.2.55"
14+wasm-bindgen = "0.2.42"
15console_error_panic_hook = "0.1.6"
15console_error_panic_hook = "0.1.6"
16−js-sys = "0.3.32"
16+js-sys = "0.3.19"
17−wasm-bindgen-futures = "0.4.5"
17+wasm-bindgen-futures = "0.3.19"
18+futures = "0.1.26"
18
19
19[dependencies.web-sys]
20[dependencies.web-sys]
20−version = "0.3.32"
21+version = "0.3.19"
21features = [
22features = [
22 "Document",
23 "Document",
23 "HtmlElement",
24 "HtmlElement",
@@ -26,4 +27,4 @@ features = [
26]
27]
27
28
28[dev-dependencies]
29[dev-dependencies]
29−wasm-bindgen-test = "0.3.5"
30+wasm-bindgen-test = "0.2.42"
examples/game-of-life/index.htmlmode 100755 → 100644+3
@@ -19,6 +19,9 @@
19 padding: 0;
19 padding: 0;
20 }
20 }
21
21
22+ .universe {
23+ }
24+
22 body {
25 body {
23 width: 100vw;
26 width: 100vw;
24 height: 100vh;
27 height: 100vh;
examples/game-of-life/src/lib.rs+13−18
@@ -1,4 +1,5 @@
1use dodrio::{bumpalo, Node, Render, RenderContext, Vdom};
1use dodrio::{bumpalo, Node, Render, RenderContext, Vdom};
2+use futures::prelude::*;
2use std::cell::RefCell;
3use std::cell::RefCell;
3use std::rc::Rc;
4use std::rc::Rc;
4use wasm_bindgen::{prelude::*, JsCast};
5use wasm_bindgen::{prelude::*, JsCast};
@@ -126,8 +127,8 @@ impl Universe {
126}
127}
127
128
128/// The rendering implementation for our Game of Life.
129/// The rendering implementation for our Game of Life.
129−impl<'a> Render<'a> for Universe {
130+impl Render for Universe {
130− fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
131+ fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
131 use dodrio::builder::*;
132 use dodrio::builder::*;
132
133
133 let mut rows = bumpalo::collections::Vec::with_capacity_in(self.height as usize, cx.bump);
134 let mut rows = bumpalo::collections::Vec::with_capacity_in(self.height as usize, cx.bump);
@@ -171,32 +172,26 @@ pub fn run() {
171 // Create a new Game of Life `Universe` render component.
172 // Create a new Game of Life `Universe` render component.
172 let universe = Universe::new();
173 let universe = Universe::new();
173
174
174− // Create a virtual DOM and mount it and the `Universe` render component to the
175+ // Create a virtual DOM and mount it and the `Hello` render component to the
175 // `<body>`.
176 // `<body>`.
176 let vdom = Vdom::new(body.as_ref(), universe);
177 let vdom = Vdom::new(body.as_ref(), universe);
177
178
178 // Kick off a loop that keeps computing a tick of the universe and then
179 // Kick off a loop that keeps computing a tick of the universe and then
179 // re-rendering on every animation frame.
180 // re-rendering on every animation frame.
180− let rc = <Rc<RefCell<Option<Closure<dyn FnMut()>>>>>::default();
181+ let rc: Rc<RefCell<Option<Closure<FnMut()>>>> = Rc::new(RefCell::new(None));
181 let rc2 = rc.clone();
182 let rc2 = rc.clone();
182 let window2 = window.clone();
183 let window2 = window.clone();
183 let weak = vdom.weak();
184 let weak = vdom.weak();
184 let f = Closure::wrap(Box::new(move || {
185 let f = Closure::wrap(Box::new(move || {
185 weak.schedule_render();
186 weak.schedule_render();
186
187
187− wasm_bindgen_futures::spawn_local({
188+ wasm_bindgen_futures::spawn_local(
188− let weak = weak.clone();
189− async move {
190− let fut = weak.with_component(|root| {
189+ weak.with_component(|root| {
191− let universe = root.unwrap_mut::<Universe>();
190+ let universe = root.unwrap_mut::<Universe>();
192− universe.tick();
191+ universe.tick();
193− });
192+ })
194−
195− if fut.await.is_err() {
196− wasm_bindgen::throw_str("impossible, we always keep the vdom alive");
193+ .map_err(|_| wasm_bindgen::throw_str("impossible, we always keep the vdom alive")),
197− }
198− }
199− });
194+ );
200
195
201 window
196 window
202 .request_animation_frame(
197 .request_animation_frame(
@@ -207,7 +202,7 @@ pub fn run() {
207 .unchecked_ref::<js_sys::Function>(),
202 .unchecked_ref::<js_sys::Function>(),
208 )
203 )
209 .unwrap_throw();
204 .unwrap_throw();
210− }) as Box<dyn FnMut()>);
205+ }) as Box<FnMut()>);
211 window2
206 window2
212 .request_animation_frame(f.as_ref().unchecked_ref::<js_sys::Function>())
207 .request_animation_frame(f.as_ref().unchecked_ref::<js_sys::Function>())
213 .unwrap_throw();
208 .unwrap_throw();
examples/hello-world/Cargo.toml+3−3
@@ -11,11 +11,11 @@ crate-type = ["cdylib"]
11
11
12[dependencies]
12[dependencies]
13dodrio = { path = "../.." }
13dodrio = { path = "../.." }
14−wasm-bindgen = "0.2.55"
14+wasm-bindgen = "0.2.42"
15console_error_panic_hook = "0.1.6"
15console_error_panic_hook = "0.1.6"
16
16
17[dependencies.web-sys]
17[dependencies.web-sys]
18−version = "0.3.32"
18+version = "0.3.19"
19features = [
19features = [
20 "Document",
20 "Document",
21 "HtmlElement",
21 "HtmlElement",
@@ -24,4 +24,4 @@ features = [
24]
24]
25
25
26[dev-dependencies]
26[dev-dependencies]
27−wasm-bindgen-test = "0.3.5"
27+wasm-bindgen-test = "0.2.42"
examples/hello-world/src/lib.rs+2−2
@@ -10,8 +10,8 @@ struct Hello {
10
10
11// The `Render` implementation describes how to render a `Hello` component into
11// The `Render` implementation describes how to render a `Hello` component into
12// HTML.
12// HTML.
13−impl<'a> Render<'a> for Hello {
13+impl Render for Hello {
14− fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
14+ fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
15 let msg = bumpalo::format!(in cx.bump, "Hello, {}!", self.who);
15 let msg = bumpalo::format!(in cx.bump, "Hello, {}!", self.who);
16 let msg = msg.into_bump_str();
16 let msg = msg.into_bump_str();
17 p(&cx).children([text(msg)]).finish()
17 p(&cx).children([text(msg)]).finish()
examples/input-form/Cargo.toml+3−3
@@ -11,11 +11,11 @@ crate-type = ["cdylib"]
11
11
12[dependencies]
12[dependencies]
13dodrio = { path = "../.." }
13dodrio = { path = "../.." }
14−wasm-bindgen = "0.2.55"
14+wasm-bindgen = "0.2.42"
15console_error_panic_hook = "0.1.6"
15console_error_panic_hook = "0.1.6"
16
16
17[dependencies.web-sys]
17[dependencies.web-sys]
18−version = "0.3.32"
18+version = "0.3.19"
19features = [
19features = [
20 "console",
20 "console",
21 "Document",
21 "Document",
@@ -29,4 +29,4 @@ features = [
29]
29]
30
30
31[dev-dependencies]
31[dev-dependencies]
32−wasm-bindgen-test = "0.3.5"
32+wasm-bindgen-test = "0.2.42"
examples/input-form/src/lib.rs+2−2
@@ -23,8 +23,8 @@ impl SayHelloTo {
23
23
24// The `Render` implementation has a text `<input>` and a `<div>` that shows a
24// The `Render` implementation has a text `<input>` and a `<div>` that shows a
25// greeting to the `<input>`'s value.
25// greeting to the `<input>`'s value.
26−impl<'a> Render<'a> for SayHelloTo {
26+impl Render for SayHelloTo {
27− fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
27+ fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
28 use dodrio::builder::*;
28 use dodrio::builder::*;
29
29
30 div(&cx)
30 div(&cx)
examples/js-component/Cargo.toml+3−3
@@ -12,12 +12,12 @@ crate-type = ["cdylib"]
12[dependencies]
12[dependencies]
13dodrio = { path = "../.." }
13dodrio = { path = "../.." }
14dodrio-js-api = { path = "../../crates/js-api" }
14dodrio-js-api = { path = "../../crates/js-api" }
15−wasm-bindgen = "0.2.55"
15+wasm-bindgen = "0.2.42"
16console_error_panic_hook = "0.1.6"
16console_error_panic_hook = "0.1.6"
17−js-sys = "0.3.32"
17+js-sys = "0.3.19"
18
18
19[dependencies.web-sys]
19[dependencies.web-sys]
20−version = "0.3.32"
20+version = "0.3.19"
21features = [
21features = [
22 "Document",
22 "Document",
23 "HtmlElement",
23 "HtmlElement",
examples/js-component/src/lib.rs+3−3
@@ -31,8 +31,8 @@ impl GreetingViaJs {
31
31
32/// Here's the `Render` implementation! This adds a `<p>` element and some text
32/// Here's the `Render` implementation! This adds a `<p>` element and some text
33/// around whatever the inner JS `Greeting` component renders.
33/// around whatever the inner JS `Greeting` component renders.
34−impl<'a> Render<'a> for GreetingViaJs {
34+impl Render for GreetingViaJs {
35− fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
35+ fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
36 use dodrio::builder::*;
36 use dodrio::builder::*;
37 p(&cx)
37 p(&cx)
38 .children([text("JavaScript says: "), self.js.render(cx)])
38 .children([text("JavaScript says: "), self.js.render(cx)])
@@ -54,7 +54,7 @@ pub fn run() {
54 // Create a new `GreetingViaJs` render component.
54 // Create a new `GreetingViaJs` render component.
55 let component = GreetingViaJs::new("World");
55 let component = GreetingViaJs::new("World");
56
56
57− // Create a virtual DOM and mount it and the `GreetingViaJs` render component to the
57+ // Create a virtual DOM and mount it and the `Hello` render component to the
58 // `<body>`.
58 // `<body>`.
59 let vdom = Vdom::new(body.as_ref(), component);
59 let vdom = Vdom::new(body.as_ref(), component);
60
60
examples/moire/Cargo.toml+9−8
@@ -8,19 +8,20 @@ edition = "2018"
8crate-type = ["cdylib"]
8crate-type = ["cdylib"]
9
9
10[dependencies]
10[dependencies]
11−cfg-if = "0.1.10"
11+cfg-if = "0.1.7"
12dodrio = { path = "../.." }
12dodrio = { path = "../.." }
13+futures = "0.1.26"
13−log = "0.4.11"
14+log = "0.4.6"
14−wasm-bindgen = "0.2.55"
15+wasm-bindgen = "0.2.42"
15−wasm-bindgen-futures = "0.4.5"
16+wasm-bindgen-futures = "0.3.19"
16
17
17# Optional dependencies for logging.
18# Optional dependencies for logging.
18console_error_panic_hook = { optional = true, version = "0.1.6" }
19console_error_panic_hook = { optional = true, version = "0.1.6" }
19−console_log = { optional = true, version = "0.2.0" }
20+console_log = { optional = true, version = "0.1.2" }
20−js-sys = "0.3.32"
21+js-sys = "0.3.19"
21
22
22[dependencies.web-sys]
23[dependencies.web-sys]
23−version = "0.3.32"
24+version = "0.3.19"
24features = [
25features = [
25 "Document",
26 "Document",
26 "Element",
27 "Element",
@@ -34,7 +35,7 @@ features = [
34]
35]
35
36
36[dev-dependencies]
37[dev-dependencies]
37−wasm-bindgen-test = "0.3.5"
38+wasm-bindgen-test = "0.2.42"
38
39
39[features]
40[features]
40logging = [
41logging = [
examples/moire/src/lib.rs+7−6
@@ -5,7 +5,8 @@ use dodrio::{bumpalo, Node, Render, RenderContext, Vdom};
5use std::cell::RefCell;
5use std::cell::RefCell;
6use std::rc::Rc;
6use std::rc::Rc;
7use std::str;
7use std::str;
8−use wasm_bindgen::{prelude::*, JsCast};
8+use wasm_bindgen::prelude::*;
9+use wasm_bindgen::JsCast;
9
10
10/// This is the main function that is automatically invoked when the wasm module
11/// This is the main function that is automatically invoked when the wasm module
11/// is loaded.
12/// is loaded.
@@ -22,12 +23,12 @@ pub fn run() {
22 // Create a new `Moire` render component.
23 // Create a new `Moire` render component.
23 let component = Moire::new();
24 let component = Moire::new();
24
25
25− // Create a virtual DOM and mount it and the `Moire` render component to the
26+ // Create a virtual DOM and mount it and the `Hello` render component to the
26 // scene.
27 // scene.
27 let vdom = Vdom::new(&scene, component);
28 let vdom = Vdom::new(&scene, component);
28
29
29 // Kick off a loop that keeps re-rendering on every animation frame.
30 // Kick off a loop that keeps re-rendering on every animation frame.
30− let rc = <Rc<RefCell<Option<Closure<dyn FnMut()>>>>>::default();
31+ let rc: Rc<RefCell<Option<Closure<FnMut()>>>> = Rc::new(RefCell::new(None));
31 let rc2 = rc.clone();
32 let rc2 = rc.clone();
32 let window2 = window.clone();
33 let window2 = window.clone();
33 let weak = vdom.weak();
34 let weak = vdom.weak();
@@ -42,7 +43,7 @@ pub fn run() {
42 .unchecked_ref::<js_sys::Function>(),
43 .unchecked_ref::<js_sys::Function>(),
43 )
44 )
44 .unwrap_throw();
45 .unwrap_throw();
45− }) as Box<dyn FnMut()>);
46+ }) as Box<FnMut()>);
46 window2
47 window2
47 .request_animation_frame(f.as_ref().unchecked_ref::<js_sys::Function>())
48 .request_animation_frame(f.as_ref().unchecked_ref::<js_sys::Function>())
48 .unwrap_throw();
49 .unwrap_throw();
@@ -104,8 +105,8 @@ impl Moire {
104 }
105 }
105}
106}
106
107
107−impl<'a> Render<'a> for Moire {
108+impl Render for Moire {
108− fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
109+ fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
109 use dodrio::builder::*;
110 use dodrio::builder::*;
110
111
111 let elapsed = web_sys::window()
112 let elapsed = web_sys::window()
examples/sierpinski-triangle/Cargo.toml+6−5
@@ -9,13 +9,14 @@ crate-type = ["cdylib"]
9
9
10[dependencies]
10[dependencies]
11dodrio = { path = "../.." }
11dodrio = { path = "../.." }
12−wasm-bindgen = "0.2.55"
12+wasm-bindgen = "0.2.42"
13console_error_panic_hook = "0.1.6"
13console_error_panic_hook = "0.1.6"
14−js-sys = "0.3.32"
14+js-sys = "0.3.19"
15−wasm-bindgen-futures = "0.4.5"
15+wasm-bindgen-futures = "0.3.19"
16+futures = "0.1.26"
16
17
17[dependencies.web-sys]
18[dependencies.web-sys]
18−version = "0.3.32"
19+version = "0.3.19"
19features = [
20features = [
20 "Document",
21 "Document",
21 "HtmlElement",
22 "HtmlElement",
@@ -25,4 +26,4 @@ features = [
25]
26]
26
27
27[dev-dependencies]
28[dev-dependencies]
28−wasm-bindgen-test = "0.3.5"
29+wasm-bindgen-test = "0.2.42"
examples/sierpinski-triangle/README.mdmode 100755 → 100644+1−1
@@ -20,5 +20,5 @@ wasm-pack build --target web
20Use any HTTP server, for example:
20Use any HTTP server, for example:
21
21
22```
22```
23−python -m SimpleHTTPServer
23+python -m http.server
24```
24```
examples/sierpinski-triangle/src/lib.rs+6−5
@@ -1,7 +1,8 @@
1use dodrio::{bumpalo, Node, Render, RenderContext, Vdom};
1use dodrio::{bumpalo, Node, Render, RenderContext, Vdom};
2use std::cell::RefCell;
2use std::cell::RefCell;
3use std::rc::Rc;
3use std::rc::Rc;
4−use wasm_bindgen::{prelude::*, JsCast};
4+use wasm_bindgen::prelude::*;
5+use wasm_bindgen::JsCast;
5use web_sys::Window;
6use web_sys::Window;
6
7
7// Triangle container defining target size.
8// Triangle container defining target size.
@@ -85,8 +86,8 @@ impl Container {
85 }
86 }
86}
87}
87
88
88−impl<'a> Render<'a> for Container {
89+impl Render for Container {
89− fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
90+ fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
90 use dodrio::builder::div;
91 use dodrio::builder::div;
91
92
92 let elapsed = web_sys::window()
93 let elapsed = web_sys::window()
@@ -111,7 +112,7 @@ impl<'a> Render<'a> for Container {
111
112
112// Kick off a loop that keeps re-rendering on every animation frame.
113// Kick off a loop that keeps re-rendering on every animation frame.
113fn animate(window: Window, vdom: Vdom) {
114fn animate(window: Window, vdom: Vdom) {
114− let rc = <Rc<RefCell<Option<Closure<dyn FnMut()>>>>>::default();
115+ let rc: Rc<RefCell<Option<Closure<FnMut()>>>> = Rc::new(RefCell::new(None));
115 let rc2 = rc.clone();
116 let rc2 = rc.clone();
116 let window2 = window.clone();
117 let window2 = window.clone();
117 let weak = vdom.weak();
118 let weak = vdom.weak();
@@ -126,7 +127,7 @@ fn animate(window: Window, vdom: Vdom) {
126 .unchecked_ref::<js_sys::Function>(),
127 .unchecked_ref::<js_sys::Function>(),
127 )
128 )
128 .unwrap_throw();
129 .unwrap_throw();
129− }) as Box<dyn FnMut()>);
130+ }) as Box<FnMut()>);
130 window2
131 window2
131 .request_animation_frame(f.as_ref().unchecked_ref::<js_sys::Function>())
132 .request_animation_frame(f.as_ref().unchecked_ref::<js_sys::Function>())
132 .unwrap_throw();
133 .unwrap_throw();
examples/todomvc/Cargo.toml+12−11
@@ -5,21 +5,22 @@ name = "dodrio-todomvc"
5version = "0.1.0"
5version = "0.1.0"
6
6
7[dependencies]
7[dependencies]
8−cfg-if = "0.1.10"
8+cfg-if = "0.1.7"
9−dodrio = { path = "../..", features = ["serde"] }
9+dodrio = { path = "../.." }
10+futures = "0.1.26"
10−js-sys = "0.3.32"
11+js-sys = "0.3.19"
11−serde = { features = ["derive"], version = "1.0.114" }
12+serde = { features = ["derive"], version = "1.0.90" }
12−serde_json = "1.0.57"
13+serde_json = "1.0.39"
13−wasm-bindgen = "0.2.55"
14+wasm-bindgen = "0.2.42"
14−wasm-bindgen-futures = "0.4.5"
15+wasm-bindgen-futures = "0.3.19"
15
16
16# Optional dependencies for logging.
17# Optional dependencies for logging.
17console_error_panic_hook = { optional = true, version = "0.1.6" }
18console_error_panic_hook = { optional = true, version = "0.1.6" }
18−console_log = { optional = true, version = "0.2.0" }
19+console_log = { optional = true, version = "0.1.2" }
19−log = { optional = true, version = "0.4.11" }
20+log = { optional = true, version = "0.4.6" }
20
21
21[dependencies.web-sys]
22[dependencies.web-sys]
22−version = "0.3.32"
23+version = "0.3.19"
23features = [
24features = [
24 "Document",
25 "Document",
25 "Event",
26 "Event",
@@ -34,7 +35,7 @@ features = [
34]
35]
35
36
36[dev-dependencies]
37[dev-dependencies]
37−wasm-bindgen-test = "0.3.5"
38+wasm-bindgen-test = "0.2.42"
38
39
39[features]
40[features]
40logging = [
41logging = [
examples/todomvc/src/router.rsmode 100755 → 100644+21−23
@@ -4,8 +4,10 @@ use crate::todos::Todos;
4use crate::utils;
4use crate::utils;
5use crate::visibility::Visibility;
5use crate::visibility::Visibility;
6use dodrio::VdomWeak;
6use dodrio::VdomWeak;
7+use futures::prelude::*;
7use std::str::FromStr;
8use std::str::FromStr;
8−use wasm_bindgen::{prelude::*, JsCast};
9+use wasm_bindgen::prelude::*;
10+use wasm_bindgen::JsCast;
9
11
10/// Start the router.
12/// Start the router.
11pub fn start(vdom: VdomWeak) {
13pub fn start(vdom: VdomWeak) {
@@ -28,27 +30,23 @@ pub fn start(vdom: VdomWeak) {
28 v
30 v
29 });
31 });
30
32
31− wasm_bindgen_futures::spawn_local({
33+ wasm_bindgen_futures::spawn_local(
32− let vdom = vdom.clone();
33− async move {
34− let _ = vdom
35− .with_component({
34+ vdom.with_component({
36− let vdom = vdom.clone();
35+ let vdom = vdom.clone();
37− move |root| {
36+ move |root| {
38− let todos = root.unwrap_mut::<Todos>();
37+ let todos = root.unwrap_mut::<Todos>();
39− // If the todos' visibility already matches the event's
38+ // If the todos' visibility already matches the event's
40− // visibility, then there is nothing to do (ha). If they
39+ // visibility, then there is nothing to do (ha). If they
41− // don't match, then we need to update the todos' visibility
40+ // don't match, then we need to update the todos' visibility
42− // and re-render.
41+ // and re-render.
43− if todos.visibility() != new_vis {
42+ if todos.visibility() != new_vis {
44− todos.set_visibility(new_vis);
43+ todos.set_visibility(new_vis);
45− vdom.schedule_render();
44+ vdom.schedule_render();
46− }
45+ }
47− }
46+ }
48− })
47+ })
49− .await;
48+ .map_err(|_| ()),
50− }
51− });
49+ );
52 };
50 };
53
51
54 // Call it once to handle the initial `#` fragment.
52 // Call it once to handle the initial `#` fragment.
@@ -59,7 +57,7 @@ pub fn start(vdom: VdomWeak) {
59 // Note that if we ever intended to unmount our todos app, we would want to
57 // Note that if we ever intended to unmount our todos app, we would want to
60 // provide a method for removing this router's event listener and cleaning
58 // provide a method for removing this router's event listener and cleaning
61 // up after ourselves.
59 // up after ourselves.
62− let on_hash_change = Closure::wrap(Box::new(on_hash_change) as Box<dyn FnMut()>);
60+ let on_hash_change = Closure::wrap(Box::new(on_hash_change) as Box<FnMut()>);
63 let window = utils::window();
61 let window = utils::window();
64 window
62 window
65 .add_event_listener_with_callback("hashchange", on_hash_change.as_ref().unchecked_ref())
63 .add_event_listener_with_callback("hashchange", on_hash_change.as_ref().unchecked_ref())
examples/todomvc/src/todo.rs+21−77
@@ -1,19 +1,14 @@
1//! Type definition and `dodrio::Render` implementation for a single todo item.
1//! Type definition and `dodrio::Render` implementation for a single todo item.
2
2
3use crate::keys;
3use crate::keys;
4−use dodrio::{Cached, Node, Render, RenderContext, RootRender, VdomWeak};
4+use dodrio::{Node, Render, RenderContext, RootRender, VdomWeak};
5use serde::{Deserialize, Serialize};
5use serde::{Deserialize, Serialize};
6use std::marker::PhantomData;
6use std::marker::PhantomData;
7use wasm_bindgen::{prelude::*, JsCast};
7use wasm_bindgen::{prelude::*, JsCast};
8
8
9/// A single todo item.
9/// A single todo item.
10−#[derive(Default)]
11−pub struct Todo<C> {
12− inner: Cached<TodoInner<C>>,
13−}
14−
15#[derive(Serialize, Deserialize)]
10#[derive(Serialize, Deserialize)]
16−struct TodoInner<C> {
11+pub struct Todo<C> {
17 id: usize,
12 id: usize,
18 title: String,
13 title: String,
19 completed: bool,
14 completed: bool,
@@ -53,87 +48,68 @@ impl<C> Todo<C> {
53 let completed = false;
48 let completed = false;
54 let edits = None;
49 let edits = None;
55 Todo {
50 Todo {
56− inner: Cached::new(TodoInner {
57− id,
51+ id,
58− title,
52+ title,
59− completed,
53+ completed,
60− edits,
54+ edits,
61− _controller: PhantomData,
55+ _controller: PhantomData,
62− }),
63 }
56 }
64 }
57 }
65
58
66 /// Set this todo item's id.
59 /// Set this todo item's id.
67 pub fn set_id(&mut self, id: usize) {
60 pub fn set_id(&mut self, id: usize) {
68− if id != self.inner.id {
69− Cached::invalidate(&self.inner);
70− }
71− self.inner.id = id;
61+ self.id = id;
72 }
62 }
73
63
74 /// Is this `Todo` complete?
64 /// Is this `Todo` complete?
75 pub fn is_complete(&self) -> bool {
65 pub fn is_complete(&self) -> bool {
76− self.inner.completed
66+ self.completed
77 }
67 }
78
68
79 /// Mark the `Todo` as complete or not.
69 /// Mark the `Todo` as complete or not.
80 pub fn set_complete(&mut self, to: bool) {
70 pub fn set_complete(&mut self, to: bool) {
81− if to != self.inner.completed {
82− Cached::invalidate(&self.inner);
83− }
84− self.inner.completed = to;
71+ self.completed = to;
85 }
72 }
86
73
87 /// Get this todo's title.
74 /// Get this todo's title.
88 pub fn title(&self) -> &str {
75 pub fn title(&self) -> &str {
89− &self.inner.title
76+ &self.title
90 }
77 }
91
78
92 /// Set this todo item's title.
79 /// Set this todo item's title.
93 pub fn set_title<S: Into<String>>(&mut self, title: S) {
80 pub fn set_title<S: Into<String>>(&mut self, title: S) {
94− let title = title.into();
81+ self.title = title.into();
95− if title != self.inner.title {
96− Cached::invalidate(&self.inner);
97− }
98− self.inner.title = title;
99 }
82 }
100
83
101 /// Set the edits for this todo.
84 /// Set the edits for this todo.
102 pub fn set_edits<S: Into<String>>(&mut self, edits: Option<S>) {
85 pub fn set_edits<S: Into<String>>(&mut self, edits: Option<S>) {
103− let edits = edits.map(Into::into);
86+ self.edits = edits.map(Into::into);
104− if edits != self.inner.edits {
105− Cached::invalidate(&self.inner);
106− }
107− self.inner.edits = edits;
108 }
87 }
109
88
110 /// Take this todo's edits, leaving `None` in their place.
89 /// Take this todo's edits, leaving `None` in their place.
111 pub fn take_edits(&mut self) -> Option<String> {
90 pub fn take_edits(&mut self) -> Option<String> {
112− if self.inner.edits.is_some() {
113− Cached::invalidate(&self.inner);
114− }
115− self.inner.edits.take()
91+ self.edits.take()
116 }
92 }
117}
93}
118
94
119−impl<'a, C: TodoActions> Render<'a> for Todo<C> {
95+impl<C: TodoActions> Render for Todo<C> {
120− fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
96+ fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
121 use dodrio::{
97 use dodrio::{
122 builder::*,
98 builder::*,
123 bumpalo::{self, collections::String},
99 bumpalo::{self, collections::String},
124 };
100 };
125
101
126− let id = self.inner.id;
102+ let id = self.id;
127− let title = self.inner.edits.as_ref().unwrap_or(&self.inner.title);
103+ let title = self.edits.as_ref().unwrap_or(&self.title);
128 let title = bumpalo::format!(in cx.bump, "{}", title).into_bump_str();
104 let title = bumpalo::format!(in cx.bump, "{}", title).into_bump_str();
129
105
130 li(&cx)
106 li(&cx)
131 .attr("class", {
107 .attr("class", {
132 let mut class = String::new_in(cx.bump);
108 let mut class = String::new_in(cx.bump);
133− if self.inner.completed {
109+ if self.completed {
134 class.push_str("completed ");
110 class.push_str("completed ");
135 }
111 }
136− if self.inner.edits.is_some() {
112+ if self.edits.is_some() {
137 class.push_str("editing");
113 class.push_str("editing");
138 }
114 }
139 class.into_bump_str()
115 class.into_bump_str()
@@ -145,7 +121,7 @@ impl<'a, C: TodoActions> Render<'a> for Todo<C> {
145 input(&cx)
121 input(&cx)
146 .attr("class", "toggle")
122 .attr("class", "toggle")
147 .attr("type", "checkbox")
123 .attr("type", "checkbox")
148− .bool_attr("checked", self.inner.completed)
124+ .bool_attr("checked", self.completed)
149 .on("click", move |root, vdom, _event| {
125 .on("click", move |root, vdom, _event| {
150 C::toggle_completed(root, vdom, id);
126 C::toggle_completed(root, vdom, id);
151 })
127 })
@@ -195,35 +171,3 @@ impl<'a, C: TodoActions> Render<'a> for Todo<C> {
195 .finish()
171 .finish()
196 }
172 }
197}
173}
198−
199−impl<C> Default for TodoInner<C> {
200− fn default() -> Self {
201− TodoInner {
202− id: Default::default(),
203− title: Default::default(),
204− completed: Default::default(),
205− edits: Default::default(),
206− _controller: PhantomData,
207− }
208− }
209−}
210−
211−impl<C> serde::Serialize for Todo<C> {
212− fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
213− where
214− S: serde::Serializer,
215− {
216− self.inner.serialize(serializer)
217− }
218−}
219−
220−impl<'de, C> Deserialize<'de> for Todo<C> {
221− fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
222− where
223− D: serde::Deserializer<'de>,
224− {
225− Ok(Todo {
226− inner: <Cached<TodoInner<C>>>::deserialize(deserializer)?,
227− })
228− }
229−}
examples/todomvc/src/todos.rsmode 100755 → 100644+6−5
@@ -9,7 +9,8 @@ use dodrio::{bumpalo, Node, Render, RenderContext, RootRender, VdomWeak};
9use serde::{Deserialize, Serialize};
9use serde::{Deserialize, Serialize};
10use std::marker::PhantomData;
10use std::marker::PhantomData;
11use std::mem;
11use std::mem;
12−use wasm_bindgen::{prelude::*, JsCast};
12+use wasm_bindgen::prelude::*;
13+use wasm_bindgen::JsCast;
13
14
14/// A collection of todos.
15/// A collection of todos.
15#[derive(Default, Serialize, Deserialize)]
16#[derive(Default, Serialize, Deserialize)]
@@ -28,7 +29,7 @@ pub struct Todos<C = Controller> {
28}
29}
29
30
30/// Actions for `Todos` that can be triggered by UI interactions.
31/// Actions for `Todos` that can be triggered by UI interactions.
31−pub trait TodosActions: 'static + TodoActions {
32+pub trait TodosActions: TodoActions {
32 /// Toggle the completion state of all todo items.
33 /// Toggle the completion state of all todo items.
33 fn toggle_all(root: &mut dyn RootRender, vdom: VdomWeak);
34 fn toggle_all(root: &mut dyn RootRender, vdom: VdomWeak);
34
35
@@ -49,7 +50,7 @@ pub trait TodosActions: 'static + TodoActions {
49impl<C> Todos<C> {
50impl<C> Todos<C> {
50 /// Construct a new todos set.
51 /// Construct a new todos set.
51 ///
52 ///
52− /// If an existing set is available in local storage, then use that,
53+ /// If an existing set is available in local storage, then us that,
53 /// otherwise create a new set.
54 /// otherwise create a new set.
54 pub fn new() -> Self
55 pub fn new() -> Self
55 where
56 where
@@ -289,8 +290,8 @@ impl<C: TodosActions> Todos<C> {
289 }
290 }
290}
291}
291
292
292−impl<'a, C: TodosActions> Render<'a> for Todos<C> {
293+impl<C: TodosActions> Render for Todos<C> {
293− fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
294+ fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
294 use dodrio::builder::*;
295 use dodrio::builder::*;
295
296
296 div(&cx)
297 div(&cx)
js/change-list-interpreter.js+7−52
@@ -86,23 +86,15 @@ const OP_TABLE = [
86 },
86 },
87
87
88 // 5
88 // 5
89− function pushReverseChild(interpreter, mem8, mem32, i) {
89+ function pushFirstChild(interpreter, mem8, mem32, i) {
90− const n = mem32[i++];
91− const parent = top(interpreter.stack);
90+ interpreter.stack.push(top(interpreter.stack).firstChild);
92− const children = parent.childNodes;
93− const child = children[children.length - n - 1];
94− interpreter.stack.push(child);
95 return i;
91 return i;
96 },
92 },
97
93
98 // 6
94 // 6
99− function popPushChild(interpreter, mem8, mem32, i) {
95+ function popPushNextSibling(interpreter, mem8, mem32, i) {
100− const n = mem32[i++];
101− interpreter.stack.pop();
96+ const node = interpreter.stack.pop();
102− const parent = top(interpreter.stack);
103− const children = parent.childNodes;
104− const child = children[n];
105− interpreter.stack.push(child);
97+ interpreter.stack.push(node.nextSibling);
106 return i;
98 return i;
107 },
99 },
108
100
@@ -234,12 +226,9 @@ const OP_TABLE = [
234 },
226 },
235
227
236 // 21
228 // 21
237− function popPushReverseChild(interpreter, mem8, mem32, i) {
229+ function pushLastChild(interpreter, mem8, mem32, i) {
238− const n = mem32[i++];
239− interpreter.stack.pop();
240 const parent = top(interpreter.stack);
230 const parent = top(interpreter.stack);
241− const children = parent.childNodes;
231+ const child = parent.lastChild;
242− const child = children[children.length - n - 1];
243 interpreter.stack.push(child);
232 interpreter.stack.push(child);
244 return i;
233 return i;
245 },
234 },
@@ -251,30 +240,6 @@ const OP_TABLE = [
251 const child = parent.childNodes[n];
240 const child = parent.childNodes[n];
252 child.remove();
241 child.remove();
253 return i;
242 return i;
254− },
255−
256− // 23
257− function setClass(interpreter, mem8, mem32, i) {
258− const classId = mem32[i++];
259− const className = interpreter.getCachedString(classId);
260− top(interpreter.stack).className = className;
261− return i;
262− },
263−
264− // 24
265− function saveTemplate(interpreter, mem8, mem32, i) {
266− const id = mem32[i++];
267− const template = top(interpreter.stack);
268− interpreter.saveTemplate(id, template.cloneNode(true));
269− return i;
270− },
271−
272− // 25
273− function pushTemplate(interpreter, mem8, mem32, i) {
274− const id = mem32[i++];
275− const template = interpreter.getTemplate(id);
276− interpreter.stack.push(template.cloneNode(true));
277− return i;
278 }
243 }
279];
244];
280
245
@@ -286,7 +251,6 @@ export class ChangeListInterpreter {
286 this.stack = [];
251 this.stack = [];
287 this.strings = new Map();
252 this.strings = new Map();
288 this.temporaries = [];
253 this.temporaries = [];
289− this.templates = new Map();
290 }
254 }
291
255
292 unmount() {
256 unmount() {
@@ -300,7 +264,6 @@ export class ChangeListInterpreter {
300 this.stack = null;
264 this.stack = null;
301 this.strings = null;
265 this.strings = null;
302 this.temporaries = null;
266 this.temporaries = null;
303− this.templates = null;
304 }
267 }
305
268
306 addChangeListRange(start, len) {
269 addChangeListRange(start, len) {
@@ -348,14 +311,6 @@ export class ChangeListInterpreter {
348 return this.strings.get(id);
311 return this.strings.get(id);
349 }
312 }
350
313
351− saveTemplate(id, template) {
352− this.templates.set(id, template);
353− }
354−
355− getTemplate(id) {
356− return this.templates.get(id);
357− }
358−
359 initEventsTrampoline(trampoline) {
314 initEventsTrampoline(trampoline) {
360 this.trampoline = trampoline;
315 this.trampoline = trampoline;
361 trampoline.mounted = true;
316 trampoline.mounted = true;
js/strace.jsdeleted−80
@@ -1,80 +0,0 @@
1−export function initStrace() {
2− instrumentAll(Element.prototype);
3− instrumentAll(Document.prototype);
4− instrumentAll(Node.prototype);
5− instrumentAll(EventTarget.prototype);
6−}
7−
8−const counts = new Map;
9−counts.total = 0;
10−
11−let timer = null;
12−
13−function log(ctorName, kind, key) {
14− counts.total += 1;
15−
16− const entry = `${kind} ${ctorName}#${key}`
17− const count = counts.get(entry);
18− if (count === undefined) {
19− counts.set(entry, 1);
20− } else {
21− counts.set(entry, count + 1);
22− }
23−
24− if (timer !== null) {
25− clearTimeout(timer);
26− }
27− timer = setTimeout(dumpAndReset, 100);
28−}
29−
30−function dumpAndReset() {
31− const data = [...counts]
32− .sort((a, b) => b[1] - a[1])
33− .map(a => ({ "DOM Method": a[0], "Count": a[1] }));
34−
35− data.push({ "DOM Method": "<total>", "Count": counts.total });
36−
37− console.table(data, ["DOM Method", "Count"]);
38−
39− counts.clear();
40− counts.total = 0;
41−}
42−
43−function instrument(proto, key, desc) {
44− const ctorName = proto.constructor.name;
45−
46− if (typeof desc.value == "function") {
47− const f = desc.value;
48− desc.value = function (...args) {
49− log(ctorName, "call", key);
50− return f.apply(this, args);
51− };
52− }
53−
54− if (typeof desc.get == "function") {
55− const get = desc.get;
56− desc.get = function (...args) {
57− log(ctorName, "get", key);
58− return get.apply(this, args);
59− };
60− }
61−
62− if (typeof desc.set == "function") {
63− const set = desc.set;
64− desc.set = function (...args) {
65− log(ctorName, "set", key);
66− return set.apply(this, args);
67− };
68− }
69−
70− Object.defineProperty(proto, key, desc);
71−}
72−
73−function instrumentAll(proto) {
74− for (const key of Object.keys(proto)) {
75− const desc = Object.getOwnPropertyDescriptor(proto, key);
76− if (desc.configurable) {
77− instrument(proto, key, desc);
78− }
79− }
80−}
src/builder.rs+3−16
@@ -282,22 +282,13 @@ where
282 /// ```
282 /// ```
283 #[inline]
283 #[inline]
284 pub fn finish(self) -> Node<'a> {
284 pub fn finish(self) -> Node<'a> {
285− let children: &'a Children = self.bump.alloc(self.children);
286− let children: &'a [Node<'a>] = children.as_ref();
287−
288− let listeners: &'a Listeners = self.bump.alloc(self.listeners);
289− let listeners: &'a [Listener<'a>] = listeners.as_ref();
290−
291− let attributes: &'a Attributes = self.bump.alloc(self.attributes);
292− let attributes: &'a [Attribute<'a>] = attributes.as_ref();
293−
294 Node::element(
285 Node::element(
295 self.bump,
286 self.bump,
296 self.key,
287 self.key,
297 self.tag_name,
288 self.tag_name,
298− listeners,
289+ self.listeners,
299− attributes,
290+ self.attributes,
300− children,
291+ self.children,
301 self.namespace,
292 self.namespace,
302 )
293 )
303 }
294 }
@@ -1010,10 +1001,6 @@ builder_constructors! {
1010 /// [`<rect>`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/rect)
1001 /// [`<rect>`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/rect)
1011 /// element.
1002 /// element.
1012 rect <> "http://www.w3.org/2000/svg";
1003 rect <> "http://www.w3.org/2000/svg";
1013− /// Build a
1014− /// [`<image>`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/image)
1015− /// element.
1016− image <> "http://www.w3.org/2000/svg";
1017}
1004}
1018
1005
1019/// Construct a text node.
1006/// Construct a text node.
src/cached.rs+13−75
@@ -3,36 +3,18 @@ use crate::{
3 node::{CachedNode, NodeKey},
3 node::{CachedNode, NodeKey},
4 Node, Render, RenderContext,
4 Node, Render, RenderContext,
5};
5};
6−use std::any::TypeId;
7use std::cell::Cell;
6use std::cell::Cell;
8use std::ops::{Deref, DerefMut};
7use std::ops::{Deref, DerefMut};
9
8
10/// A renderable that supports caching for when rendering is expensive but can
9/// A renderable that supports caching for when rendering is expensive but can
11/// generate the same DOM tree.
10/// generate the same DOM tree.
12−///
13−/// # Example
14−///
15−/// The [TodoMVC
16−/// example](https://github.com/fitzgen/dodrio/blob/master/examples/todomvc/src/todo.rs)
17−/// caches individual todo items.
18−#[derive(Clone, Debug, Default)]
11+#[derive(Clone, Debug)]
19−pub struct Cached<R>
12+pub struct Cached<R> {
20−where
21− R: Default,
22−{
23 inner: R,
13 inner: R,
24 cached: Cell<Option<CachedNode>>,
14 cached: Cell<Option<CachedNode>>,
25}
15}
26
16
27−pub_unstable_internal! {
28− #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
29− pub(crate) struct TemplateId(TypeId);
30−}
31−
32−impl<R> Cached<R>
17+impl<R> Cached<R> {
33−where
34− R: Default,
35−{
36 /// Construct a new `Cached<R>` of an inner `R`.
18 /// Construct a new `Cached<R>` of an inner `R`.
37 ///
19 ///
38 /// # Example
20 /// # Example
@@ -40,13 +22,12 @@ where
40 /// ```
22 /// ```
41 /// use dodrio::{Cached, Node, Render, RenderContext};
23 /// use dodrio::{Cached, Node, Render, RenderContext};
42 ///
24 ///
43− /// #[derive(Default)]
44 /// pub struct Counter {
25 /// pub struct Counter {
45 /// count: u32,
26 /// count: u32,
46 /// }
27 /// }
47 ///
28 ///
48− /// impl<'a> Render<'a> for Counter {
29+ /// impl Render for Counter {
49− /// fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
30+ /// fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
50 /// // ...
31 /// // ...
51 /// # unimplemented!()
32 /// # unimplemented!()
52 /// }
33 /// }
@@ -80,13 +61,12 @@ where
80 /// use dodrio::{bumpalo, Cached, Node, Render, RenderContext};
61 /// use dodrio::{bumpalo, Cached, Node, Render, RenderContext};
81 ///
62 ///
82 /// /// A component that renders to "<p>Hello, {who}!</p>"
63 /// /// A component that renders to "<p>Hello, {who}!</p>"
83− /// #[derive(Default)]
84 /// pub struct Hello {
64 /// pub struct Hello {
85 /// who: String
65 /// who: String
86 /// }
66 /// }
87 ///
67 ///
88− /// impl<'a> Render<'a> for Hello {
68+ /// impl Render for Hello {
89− /// fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
69+ /// fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
90 /// use dodrio::builder::*;
70 /// use dodrio::builder::*;
91 /// let greeting = bumpalo::format!(in cx.bump, "Hello, {}!", self.who);
71 /// let greeting = bumpalo::format!(in cx.bump, "Hello, {}!", self.who);
92 /// p(&cx)
72 /// p(&cx)
@@ -114,19 +94,7 @@ where
114 }
94 }
115}
95}
116
96
117−impl<R> Cached<R>
118−where
119− R: 'static + Default,
120−{
121− pub(crate) fn template_id() -> TemplateId {
122− TemplateId(TypeId::of::<R>())
123− }
124−}
125−
126−impl<R> Deref for Cached<R>
97+impl<R> Deref for Cached<R> {
127−where
128− R: Default,
129−{
130 type Target = R;
98 type Target = R;
131
99
132 fn deref(&self) -> &R {
100 fn deref(&self) -> &R {
@@ -134,21 +102,17 @@ where
134 }
102 }
135}
103}
136
104
137−impl<R> DerefMut for Cached<R>
105+impl<R> DerefMut for Cached<R> {
138−where
139− R: Default,
140−{
141 fn deref_mut(&mut self) -> &mut R {
106 fn deref_mut(&mut self) -> &mut R {
142 &mut self.inner
107 &mut self.inner
143 }
108 }
144}
109}
145
110
146−impl<'a, R> Render<'a> for Cached<R>
111+impl<R> Render for Cached<R>
147where
112where
148− R: 'static + Default + for<'b> Render<'b>,
113+ R: Render,
149{
114{
150− fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
115+ fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
151− let template = cx.template::<R>();
152 let cached = match self.cached.get() {
116 let cached = match self.cached.get() {
153 // This does-the-cache-contain-this-id check is necessary because
117 // This does-the-cache-contain-this-id check is necessary because
154 // the same `Cached<R>` instance can be rendered into vdom A, which
118 // the same `Cached<R>` instance can be rendered into vdom A, which
@@ -187,7 +151,7 @@ where
187 }
151 }
188 _ => {
152 _ => {
189 let mut key = NodeKey::NONE;
153 let mut key = NodeKey::NONE;
190− let id = CachedSet::insert(cx, false, template, |nested_cx| {
154+ let id = CachedSet::insert(cx, |nested_cx| {
191 let node = self.inner.render(nested_cx);
155 let node = self.inner.render(nested_cx);
192 key = node.key();
156 key = node.key();
193 node
157 node
@@ -201,29 +165,3 @@ where
201 cached.into()
165 cached.into()
202 }
166 }
203}
167}
204−
205−#[cfg(feature = "serde")]
206−impl<R> serde::Serialize for Cached<R>
207−where
208− R: Default + serde::Serialize,
209−{
210− fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
211− where
212− S: serde::Serializer,
213− {
214− self.inner.serialize(serializer)
215− }
216−}
217−
218−#[cfg(feature = "serde")]
219−impl<'de, R> serde::Deserialize<'de> for Cached<R>
220−where
221− R: Default + serde::Deserialize<'de>,
222−{
223− fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
224− where
225− D: serde::Deserializer<'de>,
226− {
227− R::deserialize(deserializer).map(Cached::new)
228− }
229−}
src/cached_set.rs+26−58
@@ -35,28 +35,6 @@ pub(crate) struct CacheEntry {
35 // once, we don't have to repeat the tracing every time we want to garbage
35 // once, we don't have to repeat the tracing every time we want to garbage
36 // collect cache entries.
36 // collect cache entries.
37 edges: FxHashSet<CacheId>,
37 edges: FxHashSet<CacheId>,
38−
39− // The template for this cached virtual subtree.
40− //
41− // When a cache entry has a template, that means that the `ChangeList` will
42− // lazily build a physical DOM subtree based on the template, and when we
43− // create new versions of this cached result, we clone the template's
44− // physical DOM subtree and then modify it, rather than building the cached
45− // result up from scratch. This is a nice win because we bounce between JS
46− // and DOM methods less often, and get the C++ DOM implementation to do most
47− // of the subtree construction for us.
48− template: Option<CacheId>,
49−
50− // Whether this entry should never be garbage collected. Typically only
51− // templates are pinned.
52− pinned: bool,
53−}
54−
55−impl From<CacheId> for u32 {
56− #[inline]
57− fn from(id: CacheId) -> u32 {
58− id.0
59− }
60}
38}
61
39
62impl CachedSet {
40impl CachedSet {
@@ -84,7 +62,7 @@ impl CachedSet {
84 }
62 }
85
63
86 self.items.retain(|id, entry| {
64 self.items.retain(|id, entry| {
87− let keep = entry.pinned || marked.contains(id);
65+ let keep = marked.contains(id);
88 if !keep {
66 if !keep {
89 let node: &Node = unsafe { &*entry.node };
67 let node: &Node = unsafe { &*entry.node };
90 registry.remove_subtree(node);
68 registry.remove_subtree(node);
@@ -130,38 +108,21 @@ impl CachedSet {
130 CacheId(next.expect_throw("ID_COUNTER overflowed"))
108 CacheId(next.expect_throw("ID_COUNTER overflowed"))
131 }
109 }
132
110
133− pub(crate) fn insert<F>(
134− cx: &mut RenderContext,
111+ pub(crate) fn insert<F>(cx: &mut RenderContext, f: F) -> CacheId
135− pinned: bool,
136− template: Option<CacheId>,
137− f: F,
138− ) -> CacheId
139 where
112 where
140 F: for<'a> FnOnce(&mut RenderContext<'a>) -> Node<'a>,
113 F: for<'a> FnOnce(&mut RenderContext<'a>) -> Node<'a>,
141 {
114 {
142− let set = cx.cached_set;
143 let bump = Bump::new();
115 let bump = Bump::new();
144− let (node, edges) = {
116+ let set = cx.cached_set;
145− let mut nested_cx = RenderContext::new(&bump, cx.cached_set, cx.templates);
117+ let mut nested_cx = RenderContext::new(&bump, set);
146− let node = f(&mut nested_cx);
118+ let node = f(&mut nested_cx);
147− let node = bump.alloc(node);
119+ let node = bump.alloc(node);
148− let edges = {
120+ let edges = {
149− let set = set.borrow();
121+ let set = set.borrow();
150− set.trace(node)
122+ set.trace(node)
151− };
152− (
153− node as *mut Node<'_> as usize as *const Node<'static>,
154− edges,
155− )
156− };
157−
158− let entry = CacheEntry {
159− bump,
160− node,
161− edges,
162− template,
163− pinned,
164 };
123 };
124+ let node = node as *mut Node<'_> as usize as *const Node<'static>;
125+ let entry = CacheEntry { bump, node, edges };
165
126
166 let mut set = set.borrow_mut();
127 let mut set = set.borrow_mut();
167 let id = set.next_id();
128 let id = set.next_id();
@@ -174,13 +135,20 @@ impl CachedSet {
174 self.items.contains_key(&id)
135 self.items.contains_key(&id)
175 }
136 }
176
137
177− /// Get the cached node and its template (if any) for the given cache id.
138+ /// Get the node for the given cache id.
178− pub fn get(&self, id: CacheId) -> (&Node, Option<CacheId>) {
139+ pub fn get(&self, mut id: CacheId) -> &Node {
140+ loop {
179− let entry = self
141+ let entry = self
180− .items
142+ .items
181− .get(&id)
143+ .get(&id)
182− .expect_throw("CachedSet::get: should have id in set");
144+ .expect_throw("CachedSet::get: should have id in set");
183− let node: &Node = unsafe { &*entry.node };
145+ let node: &Node = unsafe { &*entry.node };
184− (node, entry.template)
146+ if let NodeKind::Cached(ref c) = node.kind {
147+ id = c.id;
148+ continue;
149+ } else {
150+ return node;
151+ }
152+ }
185 }
153 }
186}
154}
src/change_list/emitter.rsmode 100755 → 100644+8−40
@@ -30,7 +30,6 @@ impl InstructionEmitter {
30
30
31 /// Invoke the given function with each of the allocated instruction
31 /// Invoke the given function with each of the allocated instruction
32 /// sequences that this emitter has built up.
32 /// sequences that this emitter has built up.
33− #[cfg_attr(feature = "xxx-unstable-internal-use-only", allow(dead_code))]
34 pub fn each_instruction_sequence<F>(&mut self, f: F)
33 pub fn each_instruction_sequence<F>(&mut self, f: F)
35 where
34 where
36 F: FnMut(&[u8]),
35 F: FnMut(&[u8]),
@@ -115,21 +114,16 @@ define_change_list_instructions! {
115 /// Stack: `[... Node] -> [... Node Node]`
114 /// Stack: `[... Node] -> [... Node Node]`
116 ///
115 ///
117 /// ```text
116 /// ```text
118− /// parent = stack.top()
119− /// child = parent.childNodes[parent.childNodes.length - n - 1]
120− /// stack.push(child)
117+ /// stack.push(stack.top().firstChild)
121 /// ```
118 /// ```
122− push_reverse_child(n) = 5,
119+ push_first_child() = 5,
123
120
124− /// Stack: `[... Node Node] -> [... Node Node]`
121+ /// Stack: `[... Node] -> [... Node]`
125 ///
122 ///
126 /// ```text
123 /// ```text
127− /// stack.pop();
124+ /// stack.push(stack.pop().nextSibling)
128− /// parent = stack.top();
129− /// child = parent.childNodes[n]
130− /// stack.push(child)
131 /// ```
125 /// ```
132− pop_push_child(n) = 6,
126+ pop_push_next_sibling() = 6,
133
127
134 /// Stack: `[... T] -> [...]`
128 /// Stack: `[... T] -> [...]`
135 ///
129 ///
@@ -246,15 +240,14 @@ define_change_list_instructions! {
246 /// ```
240 /// ```
247 insert_before() = 20,
241 insert_before() = 20,
248
242
249− /// Stack: `[... Node Node] -> [... Node Node]`
243+ /// Stack: `[... Node] -> [... Node Node]`
250 ///
244 ///
251 /// ```text
245 /// ```text
252− /// stack.pop()
253 /// parent = stack.top()
246 /// parent = stack.top()
254− /// child = parent.childNodes[parent.childNodes.length - n - 1]
247+ /// child = parent.lastChild
255 /// stack.push(child)
248 /// stack.push(child)
256 /// ```
249 /// ```
257− pop_push_reverse_child(n) = 21,
250+ push_last_child() = 21,
258
251
259 /// Stack: `[... Node] -> [... Node]`
252 /// Stack: `[... Node] -> [... Node]`
260 ///
253 ///
@@ -264,29 +257,4 @@ define_change_list_instructions! {
264 /// child.remove()
257 /// child.remove()
265 /// ```
258 /// ```
266 remove_child(n) = 22,
259 remove_child(n) = 22,
267−
268− /// Stack: `[... Node] -> [... Node]`
269− ///
270− /// ```text
271− /// class = getCachedString(class)
272− /// node = stack.top()
273− /// node.className = class
274− /// ```
275− set_class(class) = 23,
276−
277− /// Stack: `[... Node] -> [... Node]`
278− ///
279− /// ```text
280− /// template = stack.top()
281− /// saveTemplate(id, template)
282− /// ```
283− save_template(id) = 24,
284−
285− /// Stack: `[...] -> [... Node]`
286− ///
287− /// ```text
288− /// template = getTemplate(id)
289− /// stack.push(template.cloneNode(true))
290− /// ```
291− push_template(id) = 25,
292}
260}
src/change_list/mod.rs+33−153
@@ -1,29 +1,23 @@
1pub(crate) mod emitter;
1pub(crate) mod emitter;
2pub(crate) mod strings;
2pub(crate) mod strings;
3−pub(crate) mod traversal;
4
3
5// Note: has to be `pub` because of `wasm-bindgen` visibility restrictions.
4// Note: has to be `pub` because of `wasm-bindgen` visibility restrictions.
6pub mod js;
5pub mod js;
7
6
8use self::emitter::InstructionEmitter;
7use self::emitter::InstructionEmitter;
9use self::strings::{StringKey, StringsCache};
8use self::strings::{StringKey, StringsCache};
10−use self::traversal::{MoveTo, Traversal};
11−use crate::{cached_set::CacheId, Listener};
9+use crate::Listener;
12−use fxhash::FxHashSet;
13
10
14#[derive(Debug)]
11#[derive(Debug)]
15pub(crate) struct ChangeListPersistentState {
12pub(crate) struct ChangeListPersistentState {
16 strings: StringsCache,
13 strings: StringsCache,
17 emitter: InstructionEmitter,
14 emitter: InstructionEmitter,
18− traversal: Traversal,
19 interpreter: js::ChangeListInterpreter,
15 interpreter: js::ChangeListInterpreter,
20− templates: FxHashSet<CacheId>,
21}
16}
22
17
23pub(crate) struct ChangeListBuilder<'a> {
18pub(crate) struct ChangeListBuilder<'a> {
24 state: &'a mut ChangeListPersistentState,
19 state: &'a mut ChangeListPersistentState,
25 next_temporary: u32,
20 next_temporary: u32,
26− forcing_new_listeners: bool,
27}
21}
28
22
29impl Drop for ChangeListPersistentState {
23impl Drop for ChangeListPersistentState {
@@ -36,15 +30,11 @@ impl ChangeListPersistentState {
36 pub(crate) fn new(container: &crate::Element) -> ChangeListPersistentState {
30 pub(crate) fn new(container: &crate::Element) -> ChangeListPersistentState {
37 let strings = StringsCache::new();
31 let strings = StringsCache::new();
38 let emitter = InstructionEmitter::new();
32 let emitter = InstructionEmitter::new();
39− let traversal = Traversal::new();
40 let interpreter = js::ChangeListInterpreter::new(container);
33 let interpreter = js::ChangeListInterpreter::new(container);
41− let templates = Default::default();
42 ChangeListPersistentState {
34 ChangeListPersistentState {
43 strings,
35 strings,
44 emitter,
36 emitter,
45− traversal,
46 interpreter,
37 interpreter,
47− templates,
48 }
38 }
49 }
39 }
50
40
@@ -56,7 +46,6 @@ impl ChangeListPersistentState {
56 ChangeListBuilder {
46 ChangeListBuilder {
57 state: self,
47 state: self,
58 next_temporary: 0,
48 next_temporary: 0,
59− forcing_new_listeners: false,
60 }
49 }
61 }
50 }
62}
51}
@@ -70,7 +59,6 @@ cfg_if::cfg_if! {
70 // Nothing to actually apply the changes to.
59 // Nothing to actually apply the changes to.
71
60
72 self.state.emitter.reset();
61 self.state.emitter.reset();
73− self.state.traversal.reset();
74 }
62 }
75 }
63 }
76 } else {
64 } else {
@@ -86,85 +74,11 @@ cfg_if::cfg_if! {
86 interpreter.apply_changes(wasm_bindgen::memory());
74 interpreter.apply_changes(wasm_bindgen::memory());
87
75
88 self.state.emitter.reset();
76 self.state.emitter.reset();
89− self.state.traversal.reset();
90 }
77 }
91 }
78 }
92 }
79 }
93}
80}
94
81
95−/// Traversal methods.
96−impl ChangeListBuilder<'_> {
97− pub fn go_down(&mut self) {
98− self.state.traversal.down();
99− }
100−
101− pub fn go_down_to_child(&mut self, index: usize) {
102− self.state.traversal.down();
103− self.state.traversal.sibling(index);
104− }
105−
106− pub fn go_down_to_reverse_child(&mut self, index: usize) {
107− self.state.traversal.down();
108− self.state.traversal.reverse_sibling(index);
109− }
110−
111− pub fn go_up(&mut self) {
112− self.state.traversal.up();
113− }
114−
115− pub fn go_to_sibling(&mut self, index: usize) {
116− self.state.traversal.sibling(index);
117− }
118−
119− pub fn go_to_temp_sibling(&mut self, temp: u32) {
120− self.state.traversal.up();
121− self.state.traversal.down_to_temp(temp);
122− }
123−
124− pub fn go_down_to_temp_child(&mut self, temp: u32) {
125− self.state.traversal.down_to_temp(temp);
126− }
127−
128− pub fn commit_traversal(&mut self) {
129− if self.state.traversal.is_committed() {
130− return;
131− }
132−
133− for mv in self.state.traversal.commit() {
134− match mv {
135− MoveTo::Parent => {
136− debug!("emit: pop");
137− self.state.emitter.pop();
138− }
139− MoveTo::Child(n) => {
140− debug!("emit: push_child({})", n);
141− self.state.emitter.push_child(n);
142− }
143− MoveTo::ReverseChild(n) => {
144− debug!("emit: push_reverse_child({})", n);
145− self.state.emitter.push_reverse_child(n);
146− }
147− MoveTo::Sibling(n) => {
148− debug!("emit: pop_push_child({})", n);
149− self.state.emitter.pop_push_child(n);
150− }
151− MoveTo::ReverseSibling(n) => {
152− debug!("emit: pop_push_reverse_child({})", n);
153− self.state.emitter.pop_push_reverse_child(n);
154− }
155− MoveTo::TempChild(temp) => {
156− debug!("emit: push_temporary({})", temp);
157− self.state.emitter.push_temporary(temp);
158− }
159− }
160− }
161− }
162−
163− pub fn traversal_is_committed(&self) -> bool {
164− self.state.traversal.is_committed()
165− }
166−}
167−
168impl ChangeListBuilder<'_> {
82impl ChangeListBuilder<'_> {
169 pub fn next_temporary(&self) -> u32 {
83 pub fn next_temporary(&self) -> u32 {
170 self.next_temporary
84 self.next_temporary
@@ -175,7 +89,6 @@ impl ChangeListBuilder<'_> {
175 }
89 }
176
90
177 pub fn save_children_to_temporaries(&mut self, start: usize, end: usize) -> u32 {
91 pub fn save_children_to_temporaries(&mut self, start: usize, end: usize) -> u32 {
178− debug_assert!(self.traversal_is_committed());
179 debug_assert!(start < end);
92 debug_assert!(start < end);
180 let temp_base = self.next_temporary;
93 let temp_base = self.next_temporary;
181 debug!(
94 debug!(
@@ -190,19 +103,26 @@ impl ChangeListBuilder<'_> {
190 }
103 }
191
104
192 pub fn push_temporary(&self, temp: u32) {
105 pub fn push_temporary(&self, temp: u32) {
193− debug_assert!(self.traversal_is_committed());
194 debug!("emit: push_temporary({})", temp);
106 debug!("emit: push_temporary({})", temp);
195 self.state.emitter.push_temporary(temp);
107 self.state.emitter.push_temporary(temp);
196 }
108 }
197
109
110+ pub fn push_child(&self, child: usize) {
111+ debug!("emit: push_child({})", child);
112+ self.state.emitter.push_child(child as u32);
113+ }
114+
198 pub fn remove_child(&self, child: usize) {
115 pub fn remove_child(&self, child: usize) {
199− debug_assert!(self.traversal_is_committed());
200 debug!("emit: remove_child({})", child);
116 debug!("emit: remove_child({})", child);
201 self.state.emitter.remove_child(child as u32);
117 self.state.emitter.remove_child(child as u32);
202 }
118 }
203
119
120+ pub fn push_last_child(&self) {
121+ debug!("emit: push_last_child()");
122+ self.state.emitter.push_last_child();
123+ }
124+
204 pub fn insert_before(&self) {
125 pub fn insert_before(&self) {
205− debug_assert!(self.traversal_is_committed());
206 debug!("emit: insert_before()");
126 debug!("emit: insert_before()");
207 self.state.emitter.insert_before();
127 self.state.emitter.insert_before();
208 }
128 }
@@ -214,7 +134,6 @@ impl ChangeListBuilder<'_> {
214 }
134 }
215
135
216 pub fn set_text(&self, text: &str) {
136 pub fn set_text(&self, text: &str) {
217− debug_assert!(self.traversal_is_committed());
218 debug!("emit: set_text({:?})", text);
137 debug!("emit: set_text({:?})", text);
219 self.state
138 self.state
220 .emitter
139 .emitter
@@ -222,48 +141,51 @@ impl ChangeListBuilder<'_> {
222 }
141 }
223
142
224 pub fn remove_self_and_next_siblings(&self) {
143 pub fn remove_self_and_next_siblings(&self) {
225− debug_assert!(self.traversal_is_committed());
226 debug!("emit: remove_self_and_next_siblings()");
144 debug!("emit: remove_self_and_next_siblings()");
227 self.state.emitter.remove_self_and_next_siblings();
145 self.state.emitter.remove_self_and_next_siblings();
228 }
146 }
229
147
230 pub fn replace_with(&self) {
148 pub fn replace_with(&self) {
231− debug_assert!(self.traversal_is_committed());
232 debug!("emit: replace_with()");
149 debug!("emit: replace_with()");
233 self.state.emitter.replace_with();
150 self.state.emitter.replace_with();
234 }
151 }
235
152
236− pub fn set_attribute(&mut self, name: &str, value: &str, is_namespaced: bool) {
153+ pub fn set_attribute(&mut self, name: &str, value: &str) {
237− debug_assert!(self.traversal_is_committed());
238− if name == "class" && !is_namespaced {
239− let class_id = self.ensure_string(value);
240− debug!("emit: set_class({:?})", value);
154+ debug!("emit: set_attribute({:?}, {:?})", name, value);
241− self.state.emitter.set_class(class_id.into());
242− } else {
243− let name_id = self.ensure_string(name);
155+ let name_id = self.ensure_string(name);
244− let value_id = self.ensure_string(value);
156+ let value_id = self.ensure_string(value);
245− debug!("emit: set_attribute({:?}, {:?})", name, value);
246− self.state
157+ self.state
247− .emitter
158+ .emitter
248− .set_attribute(name_id.into(), value_id.into());
159+ .set_attribute(name_id.into(), value_id.into());
249− }
250 }
160 }
251
161
252 pub fn remove_attribute(&mut self, name: &str) {
162 pub fn remove_attribute(&mut self, name: &str) {
253− debug_assert!(self.traversal_is_committed());
254 debug!("emit: remove_attribute({:?})", name);
163 debug!("emit: remove_attribute({:?})", name);
255 let name_id = self.ensure_string(name);
164 let name_id = self.ensure_string(name);
256 self.state.emitter.remove_attribute(name_id.into());
165 self.state.emitter.remove_attribute(name_id.into());
257 }
166 }
258
167
168+ pub fn push_first_child(&self) {
169+ debug!("emit: push_first_child");
170+ self.state.emitter.push_first_child();
171+ }
172+
173+ pub fn pop_push_next_sibling(&self) {
174+ debug!("emit: pop_push_next_sibling");
175+ self.state.emitter.pop_push_next_sibling();
176+ }
177+
178+ pub fn pop(&self) {
179+ debug!("emit: pop");
180+ self.state.emitter.pop();
181+ }
182+
259 pub fn append_child(&self) {
183 pub fn append_child(&self) {
260− debug_assert!(self.traversal_is_committed());
261 debug!("emit: append_child()");
184 debug!("emit: append_child()");
262 self.state.emitter.append_child();
185 self.state.emitter.append_child();
263 }
186 }
264
187
265 pub fn create_text_node(&self, text: &str) {
188 pub fn create_text_node(&self, text: &str) {
266− debug_assert!(self.traversal_is_committed());
267 debug!("emit: create_text_node({:?})", text);
189 debug!("emit: create_text_node({:?})", text);
268 self.state
190 self.state
269 .emitter
191 .emitter
@@ -271,14 +193,12 @@ impl ChangeListBuilder<'_> {
271 }
193 }
272
194
273 pub fn create_element(&mut self, tag_name: &str) {
195 pub fn create_element(&mut self, tag_name: &str) {
274− debug_assert!(self.traversal_is_committed());
275 debug!("emit: create_element({:?})", tag_name);
196 debug!("emit: create_element({:?})", tag_name);
276 let tag_name_id = self.ensure_string(tag_name);
197 let tag_name_id = self.ensure_string(tag_name);
277 self.state.emitter.create_element(tag_name_id.into());
198 self.state.emitter.create_element(tag_name_id.into());
278 }
199 }
279
200
280 pub fn create_element_ns(&mut self, tag_name: &str, ns: &str) {
201 pub fn create_element_ns(&mut self, tag_name: &str, ns: &str) {
281− debug_assert!(self.traversal_is_committed());
282 debug!("emit: create_element_ns({:?}, {:?})", tag_name, ns);
202 debug!("emit: create_element_ns({:?}, {:?})", tag_name, ns);
283 let tag_name_id = self.ensure_string(tag_name);
203 let tag_name_id = self.ensure_string(tag_name);
284 let ns_id = self.ensure_string(ns);
204 let ns_id = self.ensure_string(ns);
@@ -287,19 +207,7 @@ impl ChangeListBuilder<'_> {
287 .create_element_ns(tag_name_id.into(), ns_id.into());
207 .create_element_ns(tag_name_id.into(), ns_id.into());
288 }
208 }
289
209
290− pub fn push_force_new_listeners(&mut self) -> bool {
291− let old = self.forcing_new_listeners;
292− self.forcing_new_listeners = true;
293− old
294− }
295−
296− pub fn pop_force_new_listeners(&mut self, previous: bool) {
297− debug_assert!(self.forcing_new_listeners);
298− self.forcing_new_listeners = previous;
299− }
300−
301 pub fn new_event_listener(&mut self, listener: &Listener) {
210 pub fn new_event_listener(&mut self, listener: &Listener) {
302− debug_assert!(self.traversal_is_committed());
303 debug!("emit: new_event_listener({:?})", listener);
211 debug!("emit: new_event_listener({:?})", listener);
304 let (a, b) = listener.get_callback_parts();
212 let (a, b) = listener.get_callback_parts();
305 debug_assert!(a != 0);
213 debug_assert!(a != 0);
@@ -308,13 +216,6 @@ impl ChangeListBuilder<'_> {
308 }
216 }
309
217
310 pub fn update_event_listener(&mut self, listener: &Listener) {
218 pub fn update_event_listener(&mut self, listener: &Listener) {
311− debug_assert!(self.traversal_is_committed());
312−
313− if self.forcing_new_listeners {
314− self.new_event_listener(listener);
315− return;
316− }
317−
318 debug!("emit: update_event_listener({:?})", listener);
219 debug!("emit: update_event_listener({:?})", listener);
319 let (a, b) = listener.get_callback_parts();
220 let (a, b) = listener.get_callback_parts();
320 debug_assert!(a != 0);
221 debug_assert!(a != 0);
@@ -325,29 +226,8 @@ impl ChangeListBuilder<'_> {
325 }
226 }
326
227
327 pub fn remove_event_listener(&mut self, event: &str) {
228 pub fn remove_event_listener(&mut self, event: &str) {
328− debug_assert!(self.traversal_is_committed());
329 debug!("emit: remove_event_listener({:?})", event);
229 debug!("emit: remove_event_listener({:?})", event);
330 let event_id = self.ensure_string(event);
230 let event_id = self.ensure_string(event);
331 self.state.emitter.remove_event_listener(event_id.into());
231 self.state.emitter.remove_event_listener(event_id.into());
332 }
232 }
333−
334− #[inline]
335− pub fn has_template(&mut self, id: CacheId) -> bool {
336− self.state.templates.contains(&id)
337− }
338−
339− pub fn save_template(&mut self, id: CacheId) {
340− debug_assert!(self.traversal_is_committed());
341− debug_assert!(!self.has_template(id));
342− debug!("emit: save_template({:?})", id);
343− self.state.templates.insert(id);
344− self.state.emitter.save_template(id.into());
345− }
346−
347− pub fn push_template(&mut self, id: CacheId) {
348− debug_assert!(self.traversal_is_committed());
349− debug_assert!(self.has_template(id));
350− debug!("emit: push_template({:?})", id);
351− self.state.emitter.push_template(id.into());
352− }
353}
233}
src/change_list/traversal.rsdeleted−344
@@ -1,344 +0,0 @@
1−//! Keeps track of where we are moving in a DOM tree, and shortens traversal
2−//! paths between mutations to their minimal number of operations.
3−
4−#[derive(Clone, Copy, Debug, PartialEq, Eq)]
5−pub enum MoveTo {
6− /// Move from the current node up to its parent.
7− Parent,
8−
9− /// Move to the current node's n^th child.
10− Child(u32),
11−
12− /// Move to the current node's n^th from last child.
13− ReverseChild(u32),
14−
15− /// Move to the n^th sibling. Not relative from the current
16− /// location. Absolute indexed within all of the current siblings.
17− Sibling(u32),
18−
19− /// Move to the n^th from last sibling. Not relative from the current
20− /// location. Absolute indexed within all of the current siblings.
21− ReverseSibling(u32),
22−
23− /// Move down to the given saved temporary child.
24− TempChild(u32),
25−}
26−
27−#[derive(Debug)]
28−pub struct Traversal {
29− uncommitted: Vec<MoveTo>,
30−}
31−
32−impl Traversal {
33− /// Construct a new `Traversal` with its internal storage backed by the
34− /// given bump arena.
35− pub fn new() -> Traversal {
36− Traversal {
37− uncommitted: Vec::with_capacity(32),
38− }
39− }
40−
41− /// Move the traversal up in the tree.
42− pub fn up(&mut self) {
43− match self.uncommitted.last() {
44− Some(MoveTo::Sibling(_)) | Some(MoveTo::ReverseSibling(_)) => {
45− self.uncommitted.pop();
46− self.uncommitted.push(MoveTo::Parent);
47− }
48− Some(MoveTo::TempChild(_)) | Some(MoveTo::Child(_)) | Some(MoveTo::ReverseChild(_)) => {
49− self.uncommitted.pop();
50− // And we're back at the parent.
51− }
52− _ => {
53− self.uncommitted.push(MoveTo::Parent);
54− }
55− }
56− }
57−
58− /// Move the traversal down in the tree to the first child of the current
59− /// node.
60− pub fn down(&mut self) {
61− if let Some(&MoveTo::Parent) = self.uncommitted.last() {
62− self.uncommitted.pop();
63− self.sibling(0);
64− } else {
65− self.uncommitted.push(MoveTo::Child(0));
66− }
67− }
68−
69− /// Move the traversal to the n^th sibling.
70− pub fn sibling(&mut self, index: usize) {
71− let index = index as u32;
72− match self.uncommitted.last_mut() {
73− Some(MoveTo::Sibling(ref mut n)) | Some(MoveTo::Child(ref mut n)) => {
74− *n = index;
75− }
76− Some(MoveTo::ReverseSibling(_)) => {
77− self.uncommitted.pop();
78− self.uncommitted.push(MoveTo::Sibling(index));
79− }
80− Some(MoveTo::TempChild(_)) | Some(MoveTo::ReverseChild(_)) => {
81− self.uncommitted.pop();
82− self.uncommitted.push(MoveTo::Child(index))
83− }
84− _ => {
85− self.uncommitted.push(MoveTo::Sibling(index));
86− }
87− }
88− }
89−
90− /// Move the the n^th from last sibling.
91− pub fn reverse_sibling(&mut self, index: usize) {
92− let index = index as u32;
93− match self.uncommitted.last_mut() {
94− Some(MoveTo::ReverseSibling(ref mut n)) | Some(MoveTo::ReverseChild(ref mut n)) => {
95− *n = index;
96− }
97− Some(MoveTo::Sibling(_)) => {
98− self.uncommitted.pop();
99− self.uncommitted.push(MoveTo::ReverseSibling(index));
100− }
101− Some(MoveTo::TempChild(_)) | Some(MoveTo::Child(_)) => {
102− self.uncommitted.pop();
103− self.uncommitted.push(MoveTo::ReverseChild(index))
104− }
105− _ => {
106− self.uncommitted.push(MoveTo::ReverseSibling(index));
107− }
108− }
109− }
110−
111− /// Go to the given saved temporary.
112− pub fn down_to_temp(&mut self, temp: u32) {
113− match self.uncommitted.last() {
114− Some(MoveTo::Sibling(_)) | Some(MoveTo::ReverseSibling(_)) => {
115− self.uncommitted.pop();
116− }
117− Some(MoveTo::Parent)
118− | Some(MoveTo::TempChild(_))
119− | Some(MoveTo::Child(_))
120− | Some(MoveTo::ReverseChild(_))
121− | None => {
122− // Can't remove moves to parents since we rely on their stack
123− // pops.
124− }
125− }
126− self.uncommitted.push(MoveTo::TempChild(temp));
127− }
128−
129− /// Are all the traversal's moves committed? That is, are there no moves
130− /// that have *not* been committed yet?
131− #[inline]
132− pub fn is_committed(&self) -> bool {
133− self.uncommitted.is_empty()
134− }
135−
136− /// Commit this traversals moves and return the optimized path from the last
137− /// commit.
138− #[inline]
139− pub fn commit(&mut self) -> Moves {
140− Moves {
141− inner: self.uncommitted.drain(..),
142− }
143− }
144−
145− #[inline]
146− pub fn reset(&mut self) {
147− self.uncommitted.clear();
148− }
149−}
150−
151−pub struct Moves<'a> {
152− inner: std::vec::Drain<'a, MoveTo>,
153−}
154−
155−impl Iterator for Moves<'_> {
156− type Item = MoveTo;
157−
158− #[inline]
159− fn next(&mut self) -> Option<MoveTo> {
160− self.inner.next()
161− }
162−}
163−
164−#[cfg(test)]
165−mod tests {
166− use super::*;
167−
168− #[test]
169− fn test_traversal() {
170− fn t<F>(f: F) -> Box<dyn FnMut(&mut Traversal)>
171− where
172− F: 'static + FnMut(&mut Traversal),
173− {
174− Box::new(f) as _
175− }
176−
177− for (mut traverse, expected_moves) in vec![
178− (
179− t(|t| {
180− t.down();
181− }),
182− vec![MoveTo::Child(0)],
183− ),
184− (
185− t(|t| {
186− t.up();
187− }),
188− vec![MoveTo::Parent],
189− ),
190− (
191− t(|t| {
192− t.sibling(42);
193− }),
194− vec![MoveTo::Sibling(42)],
195− ),
196− (
197− t(|t| {
198− t.down();
199− t.up();
200− }),
201− vec![],
202− ),
203− (
204− t(|t| {
205− t.down();
206− t.sibling(2);
207− t.up();
208− }),
209− vec![],
210− ),
211− (
212− t(|t| {
213− t.down();
214− t.sibling(3);
215− }),
216− vec![MoveTo::Child(3)],
217− ),
218− (
219− t(|t| {
220− t.down();
221− t.sibling(4);
222− t.sibling(8);
223− }),
224− vec![MoveTo::Child(8)],
225− ),
226− (
227− t(|t| {
228− t.sibling(1);
229− t.sibling(1);
230− }),
231− vec![MoveTo::Sibling(1)],
232− ),
233− (
234− t(|t| {
235− t.reverse_sibling(3);
236− }),
237− vec![MoveTo::ReverseSibling(3)],
238− ),
239− (
240− t(|t| {
241− t.down();
242− t.reverse_sibling(3);
243− }),
244− vec![MoveTo::ReverseChild(3)],
245− ),
246− (
247− t(|t| {
248− t.down();
249− t.reverse_sibling(3);
250− t.up();
251− }),
252− vec![],
253− ),
254− (
255− t(|t| {
256− t.down();
257− t.reverse_sibling(3);
258− t.reverse_sibling(6);
259− }),
260− vec![MoveTo::ReverseChild(6)],
261− ),
262− (
263− t(|t| {
264− t.up();
265− t.reverse_sibling(3);
266− t.reverse_sibling(6);
267− }),
268− vec![MoveTo::Parent, MoveTo::ReverseSibling(6)],
269− ),
270− (
271− t(|t| {
272− t.up();
273− t.sibling(3);
274− t.sibling(6);
275− }),
276− vec![MoveTo::Parent, MoveTo::Sibling(6)],
277− ),
278− (
279− t(|t| {
280− t.sibling(3);
281− t.sibling(6);
282− t.up();
283− }),
284− vec![MoveTo::Parent],
285− ),
286− (
287− t(|t| {
288− t.reverse_sibling(3);
289− t.reverse_sibling(6);
290− t.up();
291− }),
292− vec![MoveTo::Parent],
293− ),
294− (
295− t(|t| {
296− t.down();
297− t.down_to_temp(3);
298− }),
299− vec![MoveTo::Child(0), MoveTo::TempChild(3)],
300− ),
301− (
302− t(|t| {
303− t.down_to_temp(3);
304− t.sibling(5);
305− }),
306− vec![MoveTo::Child(5)],
307− ),
308− (
309− t(|t| {
310− t.down_to_temp(3);
311− t.reverse_sibling(5);
312− }),
313− vec![MoveTo::ReverseChild(5)],
314− ),
315− (
316− t(|t| {
317− t.down_to_temp(3);
318− t.up();
319− }),
320− vec![],
321− ),
322− (
323− t(|t| {
324− t.sibling(2);
325− t.up();
326− t.down_to_temp(3);
327− }),
328− vec![MoveTo::Parent, MoveTo::TempChild(3)],
329− ),
330− (
331− t(|t| {
332− t.up();
333− t.down_to_temp(3);
334− }),
335− vec![MoveTo::Parent, MoveTo::TempChild(3)],
336− ),
337− ] {
338− let mut traversal = Traversal::new();
339− traverse(&mut traversal);
340− let actual_moves: Vec<_> = traversal.commit().collect();
341− assert_eq!(actual_moves, expected_moves);
342− }
343− }
344−}
src/diff.rs+224−388
@@ -6,8 +6,8 @@ use crate::{
6};
6};
7use fxhash::{FxHashMap, FxHashSet};
7use fxhash::{FxHashMap, FxHashSet};
8use std::cmp::Ordering;
8use std::cmp::Ordering;
9+use std::ops::Range;
9use std::u32;
10use std::u32;
10−use wasm_bindgen::UnwrapThrowExt;
11
11
12// Diff the `old` node with the `new` node. Emits instructions to modify a
12// Diff the `old` node with the `new` node. Emits instructions to modify a
13// physical DOM node that reflects `old` into something that reflects `new`.
13// physical DOM node that reflects `old` into something that reflects `new`.
@@ -32,20 +32,17 @@ pub(crate) fn diff(
32 &NodeKind::Text(TextNode { text: old_text }),
32 &NodeKind::Text(TextNode { text: old_text }),
33 ) => {
33 ) => {
34 if new_text != old_text {
34 if new_text != old_text {
35− change_list.commit_traversal();
36 change_list.set_text(new_text);
35 change_list.set_text(new_text);
37 }
36 }
38 }
37 }
39
38
40 (&NodeKind::Text(_), &NodeKind::Element(_)) => {
39 (&NodeKind::Text(_), &NodeKind::Element(_)) => {
41− change_list.commit_traversal();
42 create(cached_set, change_list, registry, new, cached_roots);
40 create(cached_set, change_list, registry, new, cached_roots);
43 registry.remove_subtree(&old);
41 registry.remove_subtree(&old);
44 change_list.replace_with();
42 change_list.replace_with();
45 }
43 }
46
44
47 (&NodeKind::Element(_), &NodeKind::Text(_)) => {
45 (&NodeKind::Element(_), &NodeKind::Text(_)) => {
48− change_list.commit_traversal();
49 create(cached_set, change_list, registry, new, cached_roots);
46 create(cached_set, change_list, registry, new, cached_roots);
50 // Note: text nodes cannot have event listeners, so we don't need to
47 // Note: text nodes cannot have event listeners, so we don't need to
51 // remove the old node's listeners from our registry her.
48 // remove the old node's listeners from our registry her.
@@ -71,14 +68,13 @@ pub(crate) fn diff(
71 }),
68 }),
72 ) => {
69 ) => {
73 if new_tag_name != old_tag_name || new_namespace != old_namespace {
70 if new_tag_name != old_tag_name || new_namespace != old_namespace {
74− change_list.commit_traversal();
75 create(cached_set, change_list, registry, new, cached_roots);
71 create(cached_set, change_list, registry, new, cached_roots);
76 registry.remove_subtree(&old);
72 registry.remove_subtree(&old);
77 change_list.replace_with();
73 change_list.replace_with();
78 return;
74 return;
79 }
75 }
80 diff_listeners(change_list, registry, old_listeners, new_listeners);
76 diff_listeners(change_list, registry, old_listeners, new_listeners);
81− diff_attributes(change_list, old_attributes, new_attributes, new_namespace.is_some());
77+ diff_attributes(change_list, old_attributes, new_attributes);
82 diff_children(
78 diff_children(
83 cached_set,
79 cached_set,
84 change_list,
80 change_list,
@@ -98,51 +94,25 @@ pub(crate) fn diff(
98 return;
94 return;
99 }
95 }
100
96
101− let (new, new_template) = cached_set.get(new.id);
97+ let new = cached_set.get(new.id);
102− let (old, old_template) = cached_set.get(old.id);
98+ let old = cached_set.get(old.id);
103− if new_template == old_template {
104− // If they are both using the same template, then just diff the
105− // subtrees.
106− diff(cached_set, change_list, registry, old, new, cached_roots);
99+ diff(cached_set, change_list, registry, old, new, cached_roots);
107− } else {
108− // Otherwise, they are probably different enough that
109− // re-constructing the subtree from scratch should be faster.
110− // This doubly holds true if we have a new template.
111− change_list.commit_traversal();
112− create_and_replace(
113− cached_set,
114− change_list,
115− registry,
116− new_template,
117− old,
118− new,
119− cached_roots,
120− );
121− }
122 }
100 }
123
101
124 // New cached node when the old node was not cached. In this scenario,
102 // New cached node when the old node was not cached. In this scenario,
125 // we assume that they are pretty different, and it isn't worth diffing
103 // we assume that they are pretty different, and it isn't worth diffing
126 // the subtrees, so we just create the new cached node afresh.
104 // the subtrees, so we just create the new cached node afresh.
127 (&NodeKind::Cached(ref c), _) => {
105 (&NodeKind::Cached(ref c), _) => {
128− change_list.commit_traversal();
129 cached_roots.insert(c.id);
106 cached_roots.insert(c.id);
130− let (new, new_template) = cached_set.get(c.id);
107+ let new = cached_set.get(c.id);
131− create_and_replace(
108+ create(cached_set, change_list, registry, new, cached_roots);
132− cached_set,
109+ registry.remove_subtree(&old);
133− change_list,
110+ change_list.replace_with();
134− registry,
135− new_template,
136− old,
137− new,
138− cached_roots,
139− );
140 }
111 }
141
112
142 // Old cached node and new non-cached node. Again, assume that they are
113 // Old cached node and new non-cached node. Again, assume that they are
143 // probably pretty different and create the new non-cached node afresh.
114 // probably pretty different and create the new non-cached node afresh.
144 (_, &NodeKind::Cached(_)) => {
115 (_, &NodeKind::Cached(_)) => {
145− change_list.commit_traversal();
146 create(cached_set, change_list, registry, new, cached_roots);
116 create(cached_set, change_list, registry, new, cached_roots);
147 registry.remove_subtree(&old);
117 registry.remove_subtree(&old);
148 change_list.replace_with();
118 change_list.replace_with();
@@ -163,10 +133,6 @@ fn diff_listeners(
163 old: &[Listener],
133 old: &[Listener],
164 new: &[Listener],
134 new: &[Listener],
165) {
135) {
166− if !old.is_empty() || !new.is_empty() {
167− change_list.commit_traversal();
168− }
169−
170 'outer1: for new_l in new {
136 'outer1: for new_l in new {
171 unsafe {
137 unsafe {
172 // Safety relies on removing `new_l` from the registry manually at
138 // Safety relies on removing `new_l` from the registry manually at
@@ -204,26 +170,22 @@ fn diff_listeners(
204// [... node]
170// [... node]
205//
171//
206// The change list stack is left unchanged.
172// The change list stack is left unchanged.
207−fn diff_attributes(change_list: &mut ChangeListBuilder, old: &[Attribute], new: &[Attribute], is_namespaced: bool) {
173+fn diff_attributes(change_list: &mut ChangeListBuilder, old: &[Attribute], new: &[Attribute]) {
208 // Do O(n^2) passes to add/update and remove attributes, since
174 // Do O(n^2) passes to add/update and remove attributes, since
209 // there are almost always very few attributes.
175 // there are almost always very few attributes.
210 'outer: for new_attr in new {
176 'outer: for new_attr in new {
211 if new_attr.is_volatile() {
177 if new_attr.is_volatile() {
212− change_list.commit_traversal();
213− change_list.set_attribute(new_attr.name, new_attr.value, is_namespaced);
178+ change_list.set_attribute(new_attr.name, new_attr.value);
214 } else {
179 } else {
215 for old_attr in old {
180 for old_attr in old {
216 if old_attr.name == new_attr.name {
181 if old_attr.name == new_attr.name {
217 if old_attr.value != new_attr.value {
182 if old_attr.value != new_attr.value {
218− change_list.commit_traversal();
219− change_list.set_attribute(new_attr.name, new_attr.value, is_namespaced);
183+ change_list.set_attribute(new_attr.name, new_attr.value);
220 }
184 }
221 continue 'outer;
185 continue 'outer;
222 }
186 }
223 }
187 }
224−
225− change_list.commit_traversal();
226− change_list.set_attribute(new_attr.name, new_attr.value, is_namespaced);
188+ change_list.set_attribute(new_attr.name, new_attr.value);
227 }
189 }
228 }
190 }
229
191
@@ -233,8 +195,6 @@ fn diff_attributes(change_list: &mut ChangeListBuilder, old: &[Attribute], new:
233 continue 'outer2;
195 continue 'outer2;
234 }
196 }
235 }
197 }
236−
237− change_list.commit_traversal();
238 change_list.remove_attribute(old_attr.name);
198 change_list.remove_attribute(old_attr.name);
239 }
199 }
240}
200}
@@ -257,46 +217,13 @@ fn diff_children(
257) {
217) {
258 if new.is_empty() {
218 if new.is_empty() {
259 if !old.is_empty() {
219 if !old.is_empty() {
260− change_list.commit_traversal();
261 remove_all_children(change_list, registry, old);
220 remove_all_children(change_list, registry, old);
262 }
221 }
263 return;
222 return;
264 }
223 }
265
224
266− if new.len() == 1 {
267− match (old.first(), &new[0]) {
268− (
269− Some(&Node {
270− kind: NodeKind::Text(TextNode { text: old_text }),
271− }),
272− &Node {
273− kind: NodeKind::Text(TextNode { text: new_text }),
274− },
275− ) if old_text == new_text => {
276− // Don't take this fast path...
277− }
278− (
279− _,
280− &Node {
281− kind: NodeKind::Text(TextNode { text }),
282− },
283− ) => {
284− change_list.commit_traversal();
285− change_list.set_text(text);
286− for o in old {
287− registry.remove_subtree(o);
288− }
289− return;
290− }
291− (_, _) => {}
292− }
293− }
294−
295 if old.is_empty() {
225 if old.is_empty() {
296− if !new.is_empty() {
297− change_list.commit_traversal();
298− create_and_append_children(cached_set, change_list, registry, new, cached_roots);
226+ create_and_append_children(cached_set, change_list, registry, new, cached_roots);
299− }
300 return;
227 return;
301 }
228 }
302
229
@@ -457,24 +384,42 @@ fn diff_keyed_prefix(
457 new: &[Node],
384 new: &[Node],
458 cached_roots: &mut FxHashSet<CacheId>,
385 cached_roots: &mut FxHashSet<CacheId>,
459) -> KeyedPrefixResult {
386) -> KeyedPrefixResult {
460− change_list.go_down();
387+ let mut pushed = false;
461 let mut shared_prefix_count = 0;
388 let mut shared_prefix_count = 0;
462
389
463− for (i, (old, new)) in old.iter().zip(new.iter()).enumerate() {
390+ for (old, new) in old.iter().zip(new.iter()) {
464 if old.key() != new.key() {
391 if old.key() != new.key() {
465 break;
392 break;
466 }
393 }
467
394
395+ if pushed {
396+ debug_assert!(shared_prefix_count > 0);
397+ change_list.pop_push_next_sibling();
398+ } else {
399+ debug_assert_eq!(shared_prefix_count, 0);
468− change_list.go_to_sibling(i);
400+ change_list.push_first_child();
401+ pushed = true;
402+ }
403+
469 diff(cached_set, change_list, registry, old, new, cached_roots);
404 diff(cached_set, change_list, registry, old, new, cached_roots);
470 shared_prefix_count += 1;
405 shared_prefix_count += 1;
406+
407+ // At the end of the loop, the change list stack looks like
408+ //
409+ // [... parent child_we_just_diffed]
410+ debug_assert!(pushed);
471 }
411 }
472
412
473 // If that was all of the old children, then create and append the remaining
413 // If that was all of the old children, then create and append the remaining
474 // new children and we're finished.
414 // new children and we're finished.
475 if shared_prefix_count == old.len() {
415 if shared_prefix_count == old.len() {
476− change_list.go_up();
416+ debug_assert!(
417+ pushed,
418+ "we handle the case of empty children before calling this method, so
419+ `shared_prefix_count` must be greater than zero, and therefore we
420+ must have pushed in the above loop"
421+ );
477− change_list.commit_traversal();
422+ change_list.pop();
478 create_and_append_children(
423 create_and_append_children(
479 cached_set,
424 cached_set,
480 change_list,
425 change_list,
@@ -488,13 +433,17 @@ fn diff_keyed_prefix(
488 // And if that was all of the new children, then remove all of the remaining
433 // And if that was all of the new children, then remove all of the remaining
489 // old children and we're finished.
434 // old children and we're finished.
490 if shared_prefix_count == new.len() {
435 if shared_prefix_count == new.len() {
491− change_list.go_to_sibling(shared_prefix_count);
436+ // Same as above.
492− change_list.commit_traversal();
437+ debug_assert!(pushed);
438+ change_list.pop_push_next_sibling();
493− remove_self_and_next_siblings(change_list, registry, &old[shared_prefix_count..]);
439+ change_list.remove_self_and_next_siblings();
494 return KeyedPrefixResult::Finished;
440 return KeyedPrefixResult::Finished;
495 }
441 }
496
442
443+ if pushed {
444+ debug_assert!(shared_prefix_count > 0);
497− change_list.go_up();
445+ change_list.pop();
446+ }
498 KeyedPrefixResult::MoreWorkToDo(shared_prefix_count)
447 KeyedPrefixResult::MoreWorkToDo(shared_prefix_count)
499}
448}
500
449
@@ -516,7 +465,7 @@ fn diff_keyed_middle(
516 change_list: &mut ChangeListBuilder,
465 change_list: &mut ChangeListBuilder,
517 registry: &mut EventsRegistry,
466 registry: &mut EventsRegistry,
518 old: &[Node],
467 old: &[Node],
519− mut new: &[Node],
468+ new: &[Node],
520 cached_roots: &mut FxHashSet<CacheId>,
469 cached_roots: &mut FxHashSet<CacheId>,
521 shared_prefix_count: usize,
470 shared_prefix_count: usize,
522 shared_suffix_count: usize,
471 shared_suffix_count: usize,
@@ -558,17 +507,31 @@ fn diff_keyed_middle(
558 // afresh.
507 // afresh.
559 if shared_suffix_count == 0 && shared_keys.is_empty() {
508 if shared_suffix_count == 0 && shared_keys.is_empty() {
560 if shared_prefix_count == 0 {
509 if shared_prefix_count == 0 {
561− change_list.commit_traversal();
562 remove_all_children(change_list, registry, old);
510 remove_all_children(change_list, registry, old);
563 } else {
511 } else {
564− change_list.go_down_to_child(shared_prefix_count);
512+ change_list.pop_push_next_sibling();
565− change_list.commit_traversal();
566 remove_self_and_next_siblings(change_list, registry, &old[shared_prefix_count..]);
513 remove_self_and_next_siblings(change_list, registry, &old[shared_prefix_count..]);
567 }
514 }
568 create_and_append_children(cached_set, change_list, registry, new, cached_roots);
515 create_and_append_children(cached_set, change_list, registry, new, cached_roots);
569 return;
516 return;
570 }
517 }
571
518
519+ // The longest increasing subsequence within `new_index_to_old_index` in
520+ // reverse order (since `lis_with` adds the indices in reverse
521+ // order). We will leave these nodes in place in the DOM, and only move
522+ // nodes that are not part of the LIS. This results in the minimum
523+ // number of DOM nodes moved.
524+ let mut reverse_lis = Vec::with_capacity(new_index_to_old_index.len());
525+ let mut predecessors = vec![0; new_index_to_old_index.len()];
526+ let mut starts = vec![0; new_index_to_old_index.len()];
527+ longest_increasing_subsequence::lis_with(
528+ &new_index_to_old_index,
529+ &mut reverse_lis,
530+ |a, b| a < b,
531+ &mut predecessors,
532+ &mut starts,
533+ );
534+
572 // Save each of the old children whose keys are reused in the new
535 // Save each of the old children whose keys are reused in the new
573 // children.
536 // children.
574 let mut old_index_to_temp = vec![u32::MAX; old.len()];
537 let mut old_index_to_temp = vec![u32::MAX; old.len()];
@@ -582,7 +545,6 @@ fn diff_keyed_middle(
582 .unwrap_or(old.len());
545 .unwrap_or(old.len());
583
546
584 if end - start > 0 {
547 if end - start > 0 {
585− change_list.commit_traversal();
586 let mut t = change_list.save_children_to_temporaries(
548 let mut t = change_list.save_children_to_temporaries(
587 shared_prefix_count + start,
549 shared_prefix_count + start,
588 shared_prefix_count + end,
550 shared_prefix_count + end,
@@ -606,138 +568,165 @@ fn diff_keyed_middle(
606 let mut removed_count = 0;
568 let mut removed_count = 0;
607 for (i, old_child) in old.iter().enumerate().rev() {
569 for (i, old_child) in old.iter().enumerate().rev() {
608 if !shared_keys.contains(&old_child.key()) {
570 if !shared_keys.contains(&old_child.key()) {
609− registry.remove_subtree(old_child);
610− change_list.commit_traversal();
611 change_list.remove_child(i + shared_prefix_count);
571 change_list.remove_child(i + shared_prefix_count);
612 removed_count += 1;
572 removed_count += 1;
613 }
573 }
614 }
574 }
615
575
616− // If there aren't any more new children, then we are done!
576+ // Whether we have pushed a child onto the change list stack or not.
617− if new.is_empty() {
577+ let mut pushed = false;
618− return;
578+
579+ // Now iterate from the end of the new children back to the beginning,
580+ // moving old children to their new destination, diffing them, and
581+ // creating new children as necessary. Note that iterating in reverse
582+ // order lets us use `Node.prototype.insertBefore` to move/insert
583+ // children.
584+ if shared_suffix_count > 0 {
585+ change_list.push_child(old_shared_suffix_start - removed_count);
586+ pushed = true;
587+ }
588+ let mut segment_end = new.len();
589+ for lis_index in reverse_lis {
590+ // Because we use `u32::MAX` as a sentinel value representing "a child
591+ // with this key is not a member of `new`", we filter that out here.
592+ let old_index = new_index_to_old_index[lis_index];
593+ if old_index == u32::MAX as usize {
594+ continue;
595+ }
596+
597+ // A segment begins with a member of the LIS, which will remain in
598+ // place in the DOM, followed by zero or more new children that are
599+ // not members of the LIS. If one of these new children shares a key
600+ // with one of the old children, then we will move that old child in
601+ // the DOM. Otherwise, we create the new child afresh.
602+ debug_assert!(segment_end - lis_index > 0);
603+
604+ // Go through each of the non-LIS child and move-and-diff or create
605+ // it.
606+ diff_and_move_or_create_segment(
607+ cached_set,
608+ change_list,
609+ registry,
610+ old,
611+ new,
612+ cached_roots,
613+ lis_index + 1..segment_end,
614+ &new_index_to_old_index,
615+ &old_index_to_temp,
616+ &mut pushed,
617+ );
618+
619+ // Now we push the member of the LIS and diff it with its
620+ // correspondingly-keyed new child.
621+ let new_child = &new[lis_index];
622+ let temp = old_index_to_temp[old_index];
623+ debug_assert_ne!(temp, u32::MAX);
624+ if pushed {
625+ change_list.pop();
626+ }
627+ change_list.push_temporary(temp);
628+ pushed = true;
629+ diff(
630+ cached_set,
631+ change_list,
632+ registry,
633+ &old[old_index],
634+ new_child,
635+ cached_roots,
636+ );
637+
638+ segment_end = lis_index;
619 }
639 }
620
640
621− // The longest increasing subsequence within `new_index_to_old_index`. This
641+ // And now diff-and-move or create each of the non-LIS children that
622− // is the longest sequence on DOM nodes in `old` that are relatively ordered
642+ // appear before the first LIS-member.
623− // correctly within `new`. We will leave these nodes in place in the DOM,
643+ diff_and_move_or_create_segment(
624− // and only move nodes that are not part of the LIS. This results in the
644+ cached_set,
625− // maximum number of DOM nodes left in place, AKA the minimum number of DOM
645+ change_list,
626− // nodes moved.
646+ registry,
627− let mut new_index_is_in_lis = FxHashSet::default();
647+ old,
628− new_index_is_in_lis.reserve(new_index_to_old_index.len());
648+ new,
629− let mut predecessors = vec![0; new_index_to_old_index.len()];
649+ cached_roots,
630− let mut starts = vec![0; new_index_to_old_index.len()];
650+ 0..segment_end,
631− longest_increasing_subsequence::lis_with(
632 &new_index_to_old_index,
651 &new_index_to_old_index,
633− &mut new_index_is_in_lis,
652+ &old_index_to_temp,
634− |a, b| a < b,
653+ &mut pushed,
635− &mut predecessors,
636− &mut starts,
637 );
654 );
638
655
639− // Now we will iterate from the end of the new children back to the
656+ if pushed {
640− // beginning, diffing old children we are reusing and if they aren't in the
657+ change_list.pop();
641− // LIS moving them to their new destination, or creating new children. Note
642− // that iterating in reverse order lets us use `Node.prototype.insertBefore`
643− // to move/insert children.
644− //
645− // But first, we ensure that we have a child on the change list stack that
646− // we can `insertBefore`. We handle this once before looping over `new`
647− // children, so that we don't have to keep checking on every loop iteration.
648− if shared_suffix_count > 0 {
649− // There is a shared suffix after these middle children. We will be
650− // inserting before that shared suffix, so add the first child of that
651− // shared suffix to the change list stack.
652− //
653− // [... parent]
654− change_list.go_down_to_child(old_shared_suffix_start - removed_count);
655− // [... parent first_child_of_shared_suffix]
656− } else {
657− // There is no shared suffix coming after these middle children.
658− // Therefore we have to process the last child in `new` and move it to
659− // the end of the parent's children if it isn't already there.
660− let last_index = new.len() - 1;
661− let last = new.last().unwrap_throw();
662− new = &new[..new.len() - 1];
663− if shared_keys.contains(&last.key()) {
664− let old_index = new_index_to_old_index[last_index];
665− let temp = old_index_to_temp[old_index];
666− // [... parent]
667− change_list.go_down_to_temp_child(temp);
668− // [... parent last]
669− diff(
670− cached_set,
671− change_list,
672− registry,
673− &old[old_index],
674− last,
675− cached_roots,
676− );
677− if new_index_is_in_lis.contains(&last_index) {
678− // Don't move it, since it is already where it needs to be.
679− } else {
680− change_list.commit_traversal();
681− // [... parent last]
682− change_list.append_child();
683− // [... parent]
684− change_list.go_down_to_temp_child(temp);
685− // [... parent last]
686− }
687− } else {
688− change_list.commit_traversal();
689− // [... parent]
690− create(cached_set, change_list, registry, last, cached_roots);
691− // [... parent last]
692− change_list.append_child();
693− // [... parent]
694− change_list.go_down_to_reverse_child(0);
695− // [... parent last]
696− }
697 }
658 }
659+}
698
660
661+// Diff-and-then-move or create each new node in the given segment. The
662+// segment's nodes must _not_ be members of the LIS (those nodes we will diff in
663+// place elsewhere, and we should not move them nor create them afresh).
664+//
665+// On entering this function, the change list stack has the parent and
666+// optionally the next sibling after this segment of children:
667+//
668+// [... parent next_sibling] if *pushed == true
669+// [... parent] otherwise
670+//
671+// After exiting, if any children were moved or created, then `pushed` is set to
672+// true and the change list stack has the first child in this segment on
673+// top. Otherwise the stack is left as it was on entering.
674+//
675+// [... parent child] if *pushed == true
676+// [... parent] otherwise
677+fn diff_and_move_or_create_segment(
678+ cached_set: &CachedSet,
679+ change_list: &mut ChangeListBuilder,
680+ registry: &mut EventsRegistry,
681+ old: &[Node],
682+ new: &[Node],
683+ cached_roots: &mut FxHashSet<CacheId>,
684+ segment: Range<usize>,
685+ new_index_to_old_index: &[usize],
686+ old_index_to_temp: &[u32],
687+ pushed: &mut bool,
688+) {
699− for (new_index, new_child) in new.iter().enumerate().rev() {
689+ for new_index in segment.rev() {
690+ let new_child = &new[new_index];
700 let old_index = new_index_to_old_index[new_index];
691 let old_index = new_index_to_old_index[new_index];
701 if old_index == u32::MAX as usize {
692 if old_index == u32::MAX as usize {
702− debug_assert!(!shared_keys.contains(&new_child.key()));
693+ // The key is not reused. Create this new child afresh.
703− change_list.commit_traversal();
704− // [... parent successor]
705 create(cached_set, change_list, registry, new_child, cached_roots);
694 create(cached_set, change_list, registry, new_child, cached_roots);
706− // [... parent successor new_child]
707− change_list.insert_before();
708− // [... parent new_child]
709 } else {
695 } else {
710− debug_assert!(shared_keys.contains(&new_child.key()));
696+ // The key is reused. Diff it with the old node and then
697+ // move the old node into its final destination.
711 let temp = old_index_to_temp[old_index];
698 let temp = old_index_to_temp[old_index];
712 debug_assert_ne!(temp, u32::MAX);
699 debug_assert_ne!(temp, u32::MAX);
713−
714− if new_index_is_in_lis.contains(&new_index) {
715− // [... parent successor]
716− change_list.go_to_temp_sibling(temp);
717− // [... parent new_child]
718− } else {
719− change_list.commit_traversal();
720− // [... parent successor]
721− change_list.push_temporary(temp);
700+ change_list.push_temporary(temp);
722− // [... parent successor new_child]
723− change_list.insert_before();
724− // [... parent new_child]
725− }
726−
727 diff(
701 diff(
728 cached_set,
702 cached_set,
729 change_list,
703 change_list,
730 registry,
704 registry,
731− &old[old_index],
732 new_child,
705 new_child,
706+ &old[old_index],
733 cached_roots,
707 cached_roots,
734 );
708 );
735 }
709 }
736− }
737
710
711+ // At this point the change list stack can have one of two shapes.
712+ if *pushed {
713+ // [... parent next_child new_child]
714+ change_list.insert_before();
715+ // [... parent new_child]
716+ } else {
738− // [... parent child]
717+ // [... parent new_child]
718+ change_list.append_child();
719+ // [... parent]
739− change_list.go_up();
720+ change_list.push_last_child();
721+ // [... parent new_child]
722+ *pushed = true;
723+ }
724+
725+ // At the end of each loop iteration, the change list stack looks like:
726+ //
740− // [... parent]
727+ // [... parent new_child]
728+ debug_assert!(*pushed);
729+ }
741}
730}
742
731
743// Diff the suffix of keyed children that share the same keys in the same order.
732// Diff the suffix of keyed children that share the same keys in the same order.
@@ -760,11 +749,10 @@ fn diff_keyed_suffix(
760 debug_assert!(!old.is_empty());
749 debug_assert!(!old.is_empty());
761
750
762 // [... parent]
751 // [... parent]
763− change_list.go_down();
752+ change_list.push_child(new_shared_suffix_start);
764 // [... parent new_child]
753 // [... parent new_child]
765
754
766− for (i, (old_child, new_child)) in old.iter().zip(new.iter()).enumerate() {
755+ for (old_child, new_child) in old.iter().zip(new.iter()) {
767− change_list.go_to_sibling(new_shared_suffix_start + i);
768 diff(
756 diff(
769 cached_set,
757 cached_set,
770 change_list,
758 change_list,
@@ -773,10 +761,14 @@ fn diff_keyed_suffix(
773 new_child,
761 new_child,
774 cached_roots,
762 cached_roots,
775 );
763 );
764+
765+ // [... parent this_new_child]
766+ change_list.pop_push_next_sibling();
767+ // [... parent next_new_child]
776 }
768 }
777
769
778 // [... parent]
770 // [... parent]
779− change_list.go_up();
771+ change_list.pop();
780}
772}
781
773
782// Diff children that are not keyed.
774// Diff children that are not keyed.
@@ -799,14 +791,17 @@ fn diff_non_keyed_children(
799 debug_assert!(!new.is_empty());
791 debug_assert!(!new.is_empty());
800 debug_assert!(!old.is_empty());
792 debug_assert!(!old.is_empty());
801
793
802− // [... parent]
803− change_list.go_down();
804− // [... parent child]
805−
806 for (i, (new_child, old_child)) in new.iter().zip(old.iter()).enumerate() {
794 for (i, (new_child, old_child)) in new.iter().zip(old.iter()).enumerate() {
807− // [... parent prev_child]
795+ if i == 0 {
808− change_list.go_to_sibling(i);
796+ // [... parent]
809− // [... parent this_child]
797+ change_list.push_first_child();
798+ // [... parent first_child]
799+ } else {
800+ // [... parent prev_sibling]
801+ change_list.pop_push_next_sibling();
802+ // [... parent next_sibling]
803+ }
804+
810 diff(
805 diff(
811 cached_set,
806 cached_set,
812 change_list,
807 change_list,
@@ -817,20 +812,23 @@ fn diff_non_keyed_children(
817 );
812 );
818 }
813 }
819
814
815+ // Note that because `new` and `old` are not empty, the previous loop always
816+ // executes at least once, so the change list stack is now:
817+ //
818+ // [... parent child]
819+
820 match old.len().cmp(&new.len()) {
820 match old.len().cmp(&new.len()) {
821 Ordering::Greater => {
821 Ordering::Greater => {
822− // [... parent prev_child]
822+ // [... parent last_shared_child]
823− change_list.go_to_sibling(new.len());
823+ change_list.pop_push_next_sibling();
824 // [... parent first_child_to_remove]
824 // [... parent first_child_to_remove]
825− change_list.commit_traversal();
826 remove_self_and_next_siblings(change_list, registry, &old[new.len()..]);
825 remove_self_and_next_siblings(change_list, registry, &old[new.len()..]);
827 // [... parent]
826 // [... parent]
828 }
827 }
829 Ordering::Less => {
828 Ordering::Less => {
830 // [... parent last_child]
829 // [... parent last_child]
831− change_list.go_up();
830+ change_list.pop();
832 // [... parent]
831 // [... parent]
833− change_list.commit_traversal();
834 create_and_append_children(
832 create_and_append_children(
835 cached_set,
833 cached_set,
836 change_list,
834 change_list,
@@ -841,7 +839,7 @@ fn diff_non_keyed_children(
841 }
839 }
842 Ordering::Equal => {
840 Ordering::Equal => {
843 // [... parent child]
841 // [... parent child]
844− change_list.go_up();
842+ change_list.pop();
845 // [... parent]
843 // [... parent]
846 }
844 }
847 }
845 }
@@ -861,7 +859,6 @@ fn create_and_append_children(
861 new: &[Node],
859 new: &[Node],
862 cached_roots: &mut FxHashSet<CacheId>,
860 cached_roots: &mut FxHashSet<CacheId>,
863) {
861) {
864− debug_assert!(change_list.traversal_is_committed());
865 for child in new {
862 for child in new {
866 create(cached_set, change_list, registry, child, cached_roots);
863 create(cached_set, change_list, registry, child, cached_roots);
867 change_list.append_child();
864 change_list.append_child();
@@ -880,7 +877,6 @@ fn remove_all_children(
880 registry: &mut EventsRegistry,
877 registry: &mut EventsRegistry,
881 old: &[Node],
878 old: &[Node],
882) {
879) {
883− debug_assert!(change_list.traversal_is_committed());
884 for child in old {
880 for child in old {
885 registry.remove_subtree(child);
881 registry.remove_subtree(child);
886 }
882 }
@@ -903,7 +899,6 @@ fn remove_self_and_next_siblings(
903 registry: &mut EventsRegistry,
899 registry: &mut EventsRegistry,
904 old: &[Node],
900 old: &[Node],
905) {
901) {
906− debug_assert!(change_list.traversal_is_committed());
907 for child in old {
902 for child in old {
908 registry.remove_subtree(child);
903 registry.remove_subtree(child);
909 }
904 }
@@ -926,7 +921,6 @@ fn create(
926 node: &Node,
921 node: &Node,
927 cached_roots: &mut FxHashSet<CacheId>,
922 cached_roots: &mut FxHashSet<CacheId>,
928) {
923) {
929− debug_assert!(change_list.traversal_is_committed());
930 match node.kind {
924 match node.kind {
931 NodeKind::Text(TextNode { text }) => {
925 NodeKind::Text(TextNode { text }) => {
932 change_list.create_text_node(text);
926 change_list.create_text_node(text);
@@ -944,34 +938,15 @@ fn create(
944 } else {
938 } else {
945 change_list.create_element(tag_name);
939 change_list.create_element(tag_name);
946 }
940 }
947−
948 for l in listeners {
941 for l in listeners {
949 unsafe {
942 unsafe {
950 registry.add(l);
943 registry.add(l);
951 }
944 }
952 change_list.new_event_listener(l);
945 change_list.new_event_listener(l);
953 }
946 }
954−
955 for attr in attributes {
947 for attr in attributes {
956− change_list.set_attribute(&attr.name, &attr.value, namespace.is_some());
948+ change_list.set_attribute(&attr.name, &attr.value);
957 }
949 }
958−
959− // Fast path: if there is a single text child, it is faster to
960− // create-and-append the text node all at once via setting the
961− // parent's `textContent` in a single change list instruction than
962− // to emit three instructions to (1) create a text node, (2) set its
963− // text content, and finally (3) append the text node to this
964− // parent.
965− if children.len() == 1 {
966− if let Node {
967− kind: NodeKind::Text(TextNode { text }),
968− } = children[0]
969− {
970− change_list.set_text(text);
971− return;
972− }
973− }
974−
975 for child in children {
950 for child in children {
976 create(cached_set, change_list, registry, child, cached_roots);
951 create(cached_set, change_list, registry, child, cached_roots);
977 change_list.append_child();
952 change_list.append_child();
@@ -979,147 +954,8 @@ fn create(
979 }
954 }
980 NodeKind::Cached(ref c) => {
955 NodeKind::Cached(ref c) => {
981 cached_roots.insert(c.id);
956 cached_roots.insert(c.id);
982− let (node, template) = cached_set.get(c.id);
957+ let node = cached_set.get(c.id);
983− if let Some(template) = template {
984− create_with_template(
985− cached_set,
986− change_list,
987− registry,
988− template,
989− node,
990− cached_roots,
991− );
992− } else {
993− create(cached_set, change_list, registry, node, cached_roots);
958+ create(cached_set, change_list, registry, node, cached_roots)
994− }
995 }
959 }
996 }
960 }
997}
961}
998−
999−// Get or create the template.
1000−//
1001−// Upon entering this function the change list stack may be in any shape:
1002−//
1003−// [...]
1004−//
1005−// When this function returns, it leaves a freshly cloned copy of the template
1006−// on the top of the change list stack:
1007−//
1008−// [... template]
1009−#[inline]
1010−fn get_or_create_template<'a>(
1011− cached_set: &'a CachedSet,
1012− change_list: &mut ChangeListBuilder,
1013− registry: &mut EventsRegistry,
1014− cached_roots: &mut FxHashSet<CacheId>,
1015− template_id: CacheId,
1016−) -> (&'a Node<'a>, bool) {
1017− let (template, template_template) = cached_set.get(template_id);
1018− debug_assert!(
1019− template_template.is_none(),
1020− "templates should not be templated themselves"
1021− );
1022−
1023− // If we haven't already created and saved the physical DOM subtree for this
1024− // template, do that now.
1025− if change_list.has_template(template_id) {
1026− // Clone the template and push it onto the stack.
1027− //
1028− // [...]
1029− change_list.push_template(template_id);
1030− // [... template]
1031−
1032− (template, true)
1033− } else {
1034− // [...]
1035− create(cached_set, change_list, registry, template, cached_roots);
1036− // [... template]
1037− change_list.save_template(template_id);
1038− // [... template]
1039−
1040− (template, false)
1041− }
1042−}
1043−
1044−fn create_and_replace(
1045− cached_set: &CachedSet,
1046− change_list: &mut ChangeListBuilder,
1047− registry: &mut EventsRegistry,
1048− new_template: Option<CacheId>,
1049− old: &Node,
1050− new: &Node,
1051− cached_roots: &mut FxHashSet<CacheId>,
1052−) {
1053− debug_assert!(change_list.traversal_is_committed());
1054−
1055− if let Some(template_id) = new_template {
1056− let (template, needs_listeners) =
1057− get_or_create_template(cached_set, change_list, registry, cached_roots, template_id);
1058− change_list.replace_with();
1059−
1060− let mut old_forcing = None;
1061− if needs_listeners {
1062− old_forcing = Some(change_list.push_force_new_listeners());
1063− }
1064−
1065− diff(
1066− cached_set,
1067− change_list,
1068− registry,
1069− template,
1070− new,
1071− cached_roots,
1072− );
1073−
1074− if let Some(old) = old_forcing {
1075− change_list.pop_force_new_listeners(old);
1076− }
1077−
1078− change_list.commit_traversal();
1079− } else {
1080− create(cached_set, change_list, registry, new, cached_roots);
1081− change_list.replace_with();
1082− }
1083− registry.remove_subtree(old);
1084−}
1085−
1086−fn create_with_template(
1087− cached_set: &CachedSet,
1088− change_list: &mut ChangeListBuilder,
1089− registry: &mut EventsRegistry,
1090− template_id: CacheId,
1091− node: &Node,
1092− cached_roots: &mut FxHashSet<CacheId>,
1093−) {
1094− debug_assert!(change_list.traversal_is_committed());
1095−
1096− // [...]
1097− let (template, needs_listeners) =
1098− get_or_create_template(cached_set, change_list, registry, cached_roots, template_id);
1099− // [... template]
1100−
1101− // Now diff the node with its template.
1102− //
1103− // We must force adding new listeners instead of updating existing ones,
1104− // since listeners don't get cloned in `cloneNode`.
1105− let mut old_forcing = None;
1106− if needs_listeners {
1107− old_forcing = Some(change_list.push_force_new_listeners());
1108− }
1109−
1110− diff(
1111− cached_set,
1112− change_list,
1113− registry,
1114− template,
1115− node,
1116− cached_roots,
1117− );
1118−
1119− if let Some(old) = old_forcing {
1120− change_list.pop_force_new_listeners(old);
1121− }
1122−
1123− // Make sure that we come back up to the level we were at originally.
1124− change_list.commit_traversal();
1125−}
src/events.rs+2−2
@@ -86,7 +86,7 @@ cfg_if::cfg_if! {
86 callback(component, vdom_weak, event);
86 callback(component, vdom_weak, event);
87 }
87 }
88 }
88 }
89− }) as Box<dyn Fn(web_sys::Event, u32, u32)>);
89+ }) as Box<Fn(web_sys::Event, u32, u32)>);
90
90
91 (registry, closure)
91 (registry, closure)
92 }
92 }
@@ -99,7 +99,7 @@ cfg_if::cfg_if! {
99
99
100 pub(crate) fn remove_subtree(&mut self, node: &Node) {
100 pub(crate) fn remove_subtree(&mut self, node: &Node) {
101 match node.kind {
101 match node.kind {
102− NodeKind::Cached(_) | NodeKind::Text(_) => {},
102+ NodeKind::Cached(_) | NodeKind::Text(_) => return,
103 NodeKind::Element(&ElementNode {listeners, children, ..}) => {
103 NodeKind::Element(&ElementNode {listeners, children, ..}) => {
104 for l in listeners {
104 for l in listeners {
105 self.remove(l);
105 self.remove(l);
src/lib.rs+4−5
@@ -18,8 +18,8 @@
18//! }
18//! }
19//! }
19//! }
20//!
20//!
21−//! impl<'a, 'who> Render<'a> for Hello<'who> {
21+//! impl<'who> Render for Hello<'who> {
22−//! fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
22+//! fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
23//! use dodrio::builder::*;
23//! use dodrio::builder::*;
24//!
24//!
25//! let id = bumpalo::format!(in cx.bump, "hello-{}", self.who);
25//! let id = bumpalo::format!(in cx.bump, "hello-{}", self.who);
@@ -92,14 +92,13 @@ mod events;
92mod node;
92mod node;
93mod render;
93mod render;
94mod render_context;
94mod render_context;
95−mod strace;
96mod vdom;
95mod vdom;
97
96
98pub mod builder;
97pub mod builder;
99
98
100// Re-export items at the top level.
99// Re-export items at the top level.
101pub use self::cached::Cached;
100pub use self::cached::Cached;
102−pub use self::node::{Attribute, Listener, Node, NodeKey};
101+pub use self::node::{Attribute, Listener, Node};
103pub use self::render::{Render, RootRender};
102pub use self::render::{Render, RootRender};
104pub use self::render_context::RenderContext;
103pub use self::render_context::RenderContext;
105pub use self::vdom::{Vdom, VdomWeak};
104pub use self::vdom::{Vdom, VdomWeak};
@@ -123,7 +122,7 @@ cfg_if::cfg_if! {
123 /// An element node in the physical DOM.
122 /// An element node in the physical DOM.
124 pub type Element = web_sys::Element;
123 pub type Element = web_sys::Element;
125
124
126− pub(crate) type EventsTrampoline = wasm_bindgen::closure::Closure<dyn Fn(web_sys::Event, u32, u32)>;
125+ pub(crate) type EventsTrampoline = wasm_bindgen::closure::Closure<Fn(web_sys::Event, u32, u32)>;
127 }
126 }
128}
127}
129
128
src/node.rs+24−35
@@ -68,44 +68,24 @@ pub_unstable_internal! {
68 }
68 }
69}
69}
70
70
71+pub_unstable_internal! {
71−/// The key for keyed children.
72+ /// The key for keyed children.
72−///
73−/// Keys must be unique among siblings.
74−///
75−/// If any sibling is keyed, then they all must be keyed.
76−#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
73+ #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
77−pub struct NodeKey(pub(crate) u32);
74+ pub(crate) struct NodeKey(pub(crate) u32);
78−
79−impl Default for NodeKey {
80− fn default() -> NodeKey {
81− NodeKey::NONE
82− }
83}
75}
84
76
85impl NodeKey {
77impl NodeKey {
86− /// The default, lack of a key.
87 pub const NONE: NodeKey = NodeKey(u32::MAX);
78 pub const NONE: NodeKey = NodeKey(u32::MAX);
88
79
89− /// Is this key `NodeKey::NONE`?
90 #[inline]
80 #[inline]
91 pub fn is_none(&self) -> bool {
81 pub fn is_none(&self) -> bool {
92 *self == Self::NONE
82 *self == Self::NONE
93 }
83 }
94
84
95− /// Is this key not `NodeKey::NONE`?
96 #[inline]
85 #[inline]
97 pub fn is_some(&self) -> bool {
86 pub fn is_some(&self) -> bool {
98 !self.is_none()
87 !self.is_none()
99 }
88 }
100−
101− /// Create a new `NodeKey`.
102− ///
103− /// `key` must not be `u32::MAX`.
104− #[inline]
105− pub fn new(key: u32) -> Self {
106− debug_assert_ne!(key, u32::MAX);
107− NodeKey(key)
108− }
109}
89}
110
90
111/// An event listener callback function.
91/// An event listener callback function.
@@ -182,22 +162,31 @@ impl<'a> Attribute<'a> {
182}
162}
183
163
184impl<'a> Node<'a> {
164impl<'a> Node<'a> {
185− /// Low-level constructor for making a new `Node` of type element with given
165+ /// Construct a new Node of type element with given tag name and children
186− /// parts.
187− ///
188− /// This is primarily intended for JSX and templating proc-macros to compile
189− /// down into. If you are building nodes by-hand, prefer using the
190− /// `dodrio::builder::*` APIs.
191 #[inline]
166 #[inline]
192− pub fn element(
167+ pub(crate) fn element<Listeners, Attributes, Children>(
193 bump: &'a Bump,
168 bump: &'a Bump,
194 key: NodeKey,
169 key: NodeKey,
195 tag_name: &'a str,
170 tag_name: &'a str,
196− listeners: &'a [Listener<'a>],
171+ listeners: Listeners,
197− attributes: &'a [Attribute<'a>],
172+ attributes: Attributes,
198− children: &'a [Node<'a>],
173+ children: Children,
199 namespace: Option<&'a str>,
174 namespace: Option<&'a str>,
200− ) -> Node<'a> {
175+ ) -> Node<'a>
176+ where
177+ Listeners: 'a + AsRef<[Listener<'a>]>,
178+ Attributes: 'a + AsRef<[Attribute<'a>]>,
179+ Children: 'a + AsRef<[Node<'a>]>,
180+ {
181+ let children: &'a Children = bump.alloc(children);
182+ let children: &'a [Node<'a>] = children.as_ref();
183+
184+ let listeners: &'a Listeners = bump.alloc(listeners);
185+ let listeners: &'a [Listener<'a>] = listeners.as_ref();
186+
187+ let attributes: &'a Attributes = bump.alloc(attributes);
188+ let attributes: &'a [Attribute<'a>] = attributes.as_ref();
189+
201 let element = bump.alloc_with(|| ElementNode {
190 let element = bump.alloc_with(|| ElementNode {
202 key,
191 key,
203 tag_name,
192 tag_name,
src/render.rs+16−43
@@ -21,8 +21,8 @@ use wasm_bindgen::UnwrapThrowExt;
21///
21///
22/// pub struct MyComponent;
22/// pub struct MyComponent;
23///
23///
24−/// impl<'a> Render<'a> for MyComponent {
24+/// impl Render for MyComponent {
25−/// fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
25+/// fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
26/// use dodrio::builder::*;
26/// use dodrio::builder::*;
27///
27///
28/// p(&cx)
28/// p(&cx)
@@ -35,26 +35,26 @@ use wasm_bindgen::UnwrapThrowExt;
35/// }
35/// }
36/// }
36/// }
37/// ```
37/// ```
38−pub trait Render<'a> {
38+pub trait Render {
39 /// Render `self` as a virtual DOM. Use the given context's `Bump` for
39 /// Render `self` as a virtual DOM. Use the given context's `Bump` for
40 /// temporary allocations.
40 /// temporary allocations.
41− fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a>;
41+ fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a>;
42}
42}
43
43
44−impl<'a, 'r, R> Render<'a> for &'r R
44+impl<'r, R> Render for &'r R
45where
45where
46− R: Render<'a>,
46+ R: Render,
47{
47{
48− fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
48+ fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
49 (**self).render(cx)
49 (**self).render(cx)
50 }
50 }
51}
51}
52
52
53−impl<'a, R> Render<'a> for Rc<R>
53+impl<R> Render for Rc<R>
54where
54where
55− R: Render<'a>,
55+ R: Render,
56{
56{
57− fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
57+ fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
58 (**self).render(cx)
58 (**self).render(cx)
59 }
59 }
60}
60}
@@ -69,24 +69,24 @@ where
69/// You do not need to implement this trait by hand: there is a blanket
69/// You do not need to implement this trait by hand: there is a blanket
70/// implementation for all `Render` types that fulfill the `RootRender`
70/// implementation for all `Render` types that fulfill the `RootRender`
71/// requirements.
71/// requirements.
72−pub trait RootRender: Any + for<'a> Render<'a> {
72+pub trait RootRender: Any + Render {
73 /// Get this `&RootRender` trait object as an `&Any` trait object reference.
73 /// Get this `&RootRender` trait object as an `&Any` trait object reference.
74− fn as_any(&self) -> &dyn Any;
74+ fn as_any(&self) -> &Any;
75
75
76 /// Get this `&mut RootRender` trait object as an `&mut Any` trait object
76 /// Get this `&mut RootRender` trait object as an `&mut Any` trait object
77 /// reference.
77 /// reference.
78− fn as_any_mut(&mut self) -> &mut dyn Any;
78+ fn as_any_mut(&mut self) -> &mut Any;
79}
79}
80
80
81impl<T> RootRender for T
81impl<T> RootRender for T
82where
82where
83− T: Any + for<'a> Render<'a>,
83+ T: Any + Render,
84{
84{
85− fn as_any(&self) -> &dyn Any {
85+ fn as_any(&self) -> &Any {
86 self
86 self
87 }
87 }
88
88
89− fn as_any_mut(&mut self) -> &mut dyn Any {
89+ fn as_any_mut(&mut self) -> &mut Any {
90 self
90 self
91 }
91 }
92}
92}
@@ -138,31 +138,4 @@ mod tests {
138 #[allow(dead_code)]
138 #[allow(dead_code)]
139 fn takes_dyn_render(_: &dyn super::RootRender) {}
139 fn takes_dyn_render(_: &dyn super::RootRender) {}
140 }
140 }
141−
142− #[test]
143− fn render_bump_scoped_child() {
144− use crate::{builder::*, bumpalo::collections::String, Node, Render, RenderContext};
145−
146− struct Child<'a> {
147− name: &'a str,
148− }
149−
150− impl<'a> Render<'a> for Child<'a> {
151− fn render(&self, _cx: &mut RenderContext<'a>) -> Node<'a> {
152− text(self.name)
153− }
154− }
155−
156− struct Parent;
157−
158− impl<'a> Render<'a> for Parent {
159− fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
160− let child_name = String::from_str_in("child", cx.bump).into_bump_str();
161−
162− div(&cx)
163− .children([Child { name: child_name }.render(cx)])
164− .finish()
165− }
166− }
167− }
168}
141}
src/render_context.rs+2−43
@@ -1,10 +1,5 @@
1−use crate::{
2− cached::{Cached, TemplateId},
3− cached_set::{CacheId, CachedSet},
1+use crate::cached_set::CachedSet;
4− Node, Render,
5−};
6use bumpalo::Bump;
2use bumpalo::Bump;
7−use fxhash::FxHashMap;
8use std::fmt;
3use std::fmt;
9
4
10/// Common context available to all `Render` implementations.
5/// Common context available to all `Render` implementations.
@@ -28,8 +23,6 @@ pub struct RenderContext<'a> {
28
23
29 pub(crate) cached_set: &'a crate::RefCell<CachedSet>,
24 pub(crate) cached_set: &'a crate::RefCell<CachedSet>,
30
25
31− pub(crate) templates: &'a mut FxHashMap<TemplateId, Option<CacheId>>,
32−
33 // Prevent exhaustive matching on the rendering context, so we can always
26 // Prevent exhaustive matching on the rendering context, so we can always
34 // add more members in a semver-compatible way.
27 // add more members in a semver-compatible way.
35 _non_exhaustive: (),
28 _non_exhaustive: (),
@@ -45,48 +38,14 @@ impl fmt::Debug for RenderContext<'_> {
45
38
46impl<'a> RenderContext<'a> {
39impl<'a> RenderContext<'a> {
47 pub_unstable_internal! {
40 pub_unstable_internal! {
48− pub(crate) fn new(
49− bump: &'a Bump,
50− cached_set: &'a crate::RefCell<CachedSet>,
41+ pub(crate) fn new(bump: &'a Bump, cached_set: &'a crate::RefCell<CachedSet>) -> Self {
51− templates: &'a mut FxHashMap<TemplateId, Option<CacheId>>
52− ) -> Self {
53 RenderContext {
42 RenderContext {
54 bump,
43 bump,
55 cached_set,
44 cached_set,
56− templates,
57 _non_exhaustive: (),
45 _non_exhaustive: (),
58 }
46 }
59 }
47 }
60 }
48 }
61−
62− pub(crate) fn cache<F>(&mut self, pinned: bool, template: Option<CacheId>, f: F) -> CacheId
63− where
64− F: for<'b> FnOnce(&mut RenderContext<'b>) -> Node<'b>,
65− {
66− CachedSet::insert(self, pinned, template, f)
67− }
68−
69− /// Get or create the cached template for `Cached<R>`.
70− pub(crate) fn template<R>(&mut self) -> Option<CacheId>
71− where
72− R: 'static + Default + for<'b> Render<'b>,
73− {
74− let template_id = Cached::<R>::template_id();
75− if let Some(cache_id) = self.templates.get(&template_id).cloned() {
76− return cache_id;
77− }
78−
79− // Prevent re-entrancy from infinite looping. Any attempts to get `R`'s
80− // template while constructing the template will simply fail to use the
81− // templated fast path.
82− self.templates.insert(template_id, None);
83−
84− // Render the default `R` and save that as the template for all
85− // `Cached<R>`s.
86− let cache_id = self.cache(true, None, |nested_cx| R::default().render(nested_cx));
87− self.templates.insert(template_id, Some(cache_id));
88− Some(cache_id)
89− }
90}
49}
91
50
92impl<'a, 'b> From<&'b RenderContext<'a>> for &'a Bump {
51impl<'a, 'b> From<&'b RenderContext<'a>> for &'a Bump {
src/strace.rsdeleted−22
@@ -1,22 +0,0 @@
1−cfg_if::cfg_if! {
2− if #[cfg(feature = "xxx-unstable-strace")] {
3− use wasm_bindgen::prelude::*;
4−
5− #[wasm_bindgen(module = "/js/strace.js")]
6− extern "C" {
7− #[wasm_bindgen(js_name = initStrace)]
8− fn really_init_strace();
9− }
10−
11− pub fn init_strace() {
12− use std::sync::Once;
13− static STRACE: Once = Once::new();
14− STRACE.call_once(|| {
15− really_init_strace();
16− });
17− }
18− } else {
19− #[inline]
20− pub fn init_strace() {}
21− }
22−}
src/vdom.rs+80−93
@@ -1,16 +1,14 @@
1use super::change_list::ChangeListPersistentState;
1use super::change_list::ChangeListPersistentState;
2use super::RootRender;
2use super::RootRender;
3−use crate::cached::TemplateId;
4−use crate::cached_set::{CacheId, CachedSet};
3+use crate::cached_set::CachedSet;
5use crate::events::EventsRegistry;
4use crate::events::EventsRegistry;
6use crate::node::{Node, NodeKey};
5use crate::node::{Node, NodeKey};
7use crate::RenderContext;
6use crate::RenderContext;
8use bumpalo::Bump;
7use bumpalo::Bump;
9−use fxhash::FxHashMap;
8+use futures::future::Future;
10use std::cell::Cell;
9use std::cell::Cell;
11use std::cell::RefCell;
10use std::cell::RefCell;
12use std::fmt;
11use std::fmt;
13−use std::future::Future;
14use std::mem;
12use std::mem;
15use std::mem::ManuallyDrop;
13use std::mem::ManuallyDrop;
16use std::rc::{Rc, Weak};
14use std::rc::{Rc, Weak};
@@ -55,7 +53,7 @@ pub(crate) struct VdomInnerExclusive {
55 // Always `Some` except just before we drop. Just an option so that
53 // Always `Some` except just before we drop. Just an option so that
56 // `unmount` can take the component out but we can still have a Drop
54 // `unmount` can take the component out but we can still have a Drop
57 // implementation.
55 // implementation.
58− component: Option<Box<dyn RootRender>>,
56+ component: Option<Box<RootRender>>,
59
57
60 dom_buffers: Option<[Bump; 2]>,
58 dom_buffers: Option<[Bump; 2]>,
61 change_list: ManuallyDrop<ChangeListPersistentState>,
59 change_list: ManuallyDrop<ChangeListPersistentState>,
@@ -63,7 +61,6 @@ pub(crate) struct VdomInnerExclusive {
63 events_registry: Option<Rc<RefCell<EventsRegistry>>>,
61 events_registry: Option<Rc<RefCell<EventsRegistry>>>,
64 events_trampoline: Option<crate::EventsTrampoline>,
62 events_trampoline: Option<crate::EventsTrampoline>,
65 cached_set: crate::RefCell<CachedSet>,
63 cached_set: crate::RefCell<CachedSet>,
66− templates: FxHashMap<TemplateId, Option<CacheId>>,
67
64
68 // Actually a reference into `self.dom_buffers[0]` or if `self.component` is
65 // Actually a reference into `self.dom_buffers[0]` or if `self.component` is
69 // caching renders, into `self.component`'s bump.
66 // caching renders, into `self.component`'s bump.
@@ -158,24 +155,18 @@ impl Vdom {
158 where
155 where
159 R: RootRender,
156 R: RootRender,
160 {
157 {
161− Self::with_boxed_root_render(container, Box::new(component) as Box<dyn RootRender>)
158+ Self::with_boxed_root_render(container, Box::new(component) as Box<RootRender>)
162 }
159 }
163
160
164 /// Construct a `Vdom` with the already-boxed-as-a-trait-object root
161 /// Construct a `Vdom` with the already-boxed-as-a-trait-object root
165 /// rendering component.
162 /// rendering component.
166− pub fn with_boxed_root_render(
163+ pub fn with_boxed_root_render(container: &crate::Element, component: Box<RootRender>) -> Vdom {
167− container: &crate::Element,
168− component: Box<dyn RootRender>,
169− ) -> Vdom {
170− crate::strace::init_strace();
171−
172 let dom_buffers = [Bump::new(), Bump::new()];
164 let dom_buffers = [Bump::new(), Bump::new()];
173 let change_list = ManuallyDrop::new(ChangeListPersistentState::new(container));
165 let change_list = ManuallyDrop::new(ChangeListPersistentState::new(container));
174
166
175 // Create a dummy `<div/>` in our container.
167 // Create a dummy `<div/>` in our container.
176 initialize_container(container);
168 initialize_container(container);
177− let current_root =
178− Node::element(&dom_buffers[0], NodeKey::NONE, "div", &[], &[], &[], None);
169+ let current_root = Node::element(&dom_buffers[0], NodeKey::NONE, "div", [], [], [], None);
179 let current_root = Some(unsafe { extend_node_lifetime(current_root) });
170 let current_root = Some(unsafe { extend_node_lifetime(current_root) });
180
171
181 let container = container.clone();
172 let container = container.clone();
@@ -192,7 +183,6 @@ impl Vdom {
192 events_registry: None,
183 events_registry: None,
193 events_trampoline: None,
184 events_trampoline: None,
194 cached_set: crate::RefCell::new(Default::default()),
185 cached_set: crate::RefCell::new(Default::default()),
195− templates: Default::default(),
196 }),
186 }),
197 });
187 });
198
188
@@ -220,7 +210,7 @@ impl Vdom {
220 R: RootRender,
210 R: RootRender,
221 {
211 {
222 let mut exclusive = self.inner.exclusive.borrow_mut();
212 let mut exclusive = self.inner.exclusive.borrow_mut();
223− let component = Box::new(component) as Box<dyn RootRender>;
213+ let component = Box::new(component) as Box<RootRender>;
224 exclusive.component = Some(component);
214 exclusive.component = Some(component);
225 exclusive.render();
215 exclusive.render();
226 }
216 }
@@ -240,7 +230,7 @@ impl Vdom {
240 /// Unmount this virtual DOM, unregister its event listeners, and return its
230 /// Unmount this virtual DOM, unregister its event listeners, and return its
241 /// root render component.
231 /// root render component.
242 #[inline]
232 #[inline]
243− pub fn unmount(self) -> Box<dyn RootRender> {
233+ pub fn unmount(self) -> Box<RootRender> {
244 Rc::try_unwrap(self.inner.clone())
234 Rc::try_unwrap(self.inner.clone())
245 .map_err(|_| ())
235 .map_err(|_| ())
246 .unwrap_throw()
236 .unwrap_throw()
@@ -272,8 +262,7 @@ impl VdomInnerExclusive {
272 dom_buffers[1].reset();
262 dom_buffers[1].reset();
273
263
274 // Render the new current contents into the inactive bump arena.
264 // Render the new current contents into the inactive bump arena.
275− let mut cx =
276− RenderContext::new(&dom_buffers[1], &self.cached_set, &mut self.templates);
265+ let mut cx = RenderContext::new(&dom_buffers[1], &self.cached_set);
277 let new_contents = self.component.as_ref().unwrap_throw().render(&mut cx);
266 let new_contents = self.component.as_ref().unwrap_throw().render(&mut cx);
278 let new_contents = extend_node_lifetime(new_contents);
267 let new_contents = extend_node_lifetime(new_contents);
279
268
@@ -326,7 +315,7 @@ impl VdomInnerExclusive {
326 }
315 }
327}
316}
328
317
329−fn request_animation_frame(f: &Closure<dyn FnMut()>) {
318+fn request_animation_frame(f: &Closure<FnMut()>) {
330 web_sys::window()
319 web_sys::window()
331 .expect_throw("should have a window")
320 .expect_throw("should have a window")
332 .request_animation_frame(f.as_ref().unchecked_ref())
321 .request_animation_frame(f.as_ref().unchecked_ref())
@@ -343,7 +332,7 @@ where
343 let f = Closure::wrap(Box::new(move || {
332 let f = Closure::wrap(Box::new(move || {
344 *g.borrow_mut() = None;
333 *g.borrow_mut() = None;
345 f();
334 f();
346− }) as Box<dyn FnMut()>);
335+ }) as Box<FnMut()>);
347 request_animation_frame(&f);
336 request_animation_frame(&f);
348
337
349 *h.borrow_mut() = Some(f);
338 *h.borrow_mut() = Some(f);
@@ -374,23 +363,25 @@ impl VdomWeak {
374 /// Replace the root rendering component with the new `root`.
363 /// Replace the root rendering component with the new `root`.
375 ///
364 ///
376 /// Returns a future that resolves to the *old* root component.
365 /// Returns a future that resolves to the *old* root component.
377− pub async fn set_component(
366+ pub fn set_component(
378 self,
367 self,
379 root: Box<dyn RootRender>,
368 root: Box<dyn RootRender>,
380− ) -> Result<Box<dyn RootRender + 'static>, VdomDroppedError> {
369+ ) -> impl Future<Item = Box<dyn RootRender + 'static>, Error = VdomDroppedError> {
370+ futures::future::ok(self.inner.upgrade())
371+ .and_then(|inner| inner.ok_or(()))
381− let inner = self.inner.upgrade().ok_or(VdomDroppedError {})?;
372+ .map_err(|_| VdomDroppedError {})
382−
373+ .and_then(|inner| {
383− // Wait for a new tick of the micro-task queue
384− let _ = JsFuture::from(js_sys::Promise::resolve(&JsValue::null())).await;
374+ let promise = js_sys::Promise::resolve(&JsValue::null());
385−
375+ JsFuture::from(promise)
376+ .map_err(|_| VdomDroppedError {})
377+ .and_then(move |_| {
386− let old = {
378+ let old = {
387− let mut exclusive = inner.exclusive.borrow_mut();
379+ let mut exclusive = inner.exclusive.borrow_mut();
388− mem::replace(&mut *exclusive.component.as_mut().unwrap_throw(), root)
380+ mem::replace(&mut *exclusive.component.as_mut().unwrap_throw(), root)
389− };
381+ };
390−
391− VdomWeak::new(&inner).render().await?;
382+ VdomWeak::new(&inner).render().map(|_| old)
392−
383+ })
393− Ok(old)
384+ })
394 }
385 }
395
386
396 /// Execute `f` with a reference to this virtual DOM's root rendering
387 /// Execute `f` with a reference to this virtual DOM's root rendering
@@ -398,18 +389,24 @@ impl VdomWeak {
398 ///
389 ///
399 /// To ensure exclusive access to the root rendering component, the
390 /// To ensure exclusive access to the root rendering component, the
400 /// invocation takes place on a new tick of the micro-task queue.
391 /// invocation takes place on a new tick of the micro-task queue.
401− pub async fn with_component<F, T>(&self, f: F) -> Result<T, VdomDroppedError>
392+ pub fn with_component<F, T>(&self, f: F) -> impl Future<Item = T, Error = VdomDroppedError>
402 where
393 where
403 F: 'static + FnOnce(&mut dyn RootRender) -> T,
394 F: 'static + FnOnce(&mut dyn RootRender) -> T,
404 {
395 {
396+ futures::future::ok(self.inner.upgrade())
397+ .and_then(|inner| inner.ok_or(()))
405− let inner = self.inner.upgrade().ok_or(VdomDroppedError {})?;
398+ .map_err(|_| VdomDroppedError {})
406−
399+ .and_then(|inner| {
407− // Wait for a new tick of the micro-task queue
400+ let mut f = Some(f);
408− let _ = JsFuture::from(js_sys::Promise::resolve(&JsValue::null())).await;
401+ let promise = js_sys::Promise::resolve(&JsValue::null());
409−
402+ JsFuture::from(promise)
403+ .map_err(|_| VdomDroppedError {})
404+ .map(move |_| {
405+ let f = f.take().unwrap_throw();
410− let mut exclusive = inner.exclusive.borrow_mut();
406+ let mut exclusive = inner.exclusive.borrow_mut();
411−
412− Ok(f(exclusive.component_raw_mut()))
407+ f(exclusive.component_raw_mut())
408+ })
409+ })
413 }
410 }
414
411
415 /// Schedule a render to occur during the next animation frame.
412 /// Schedule a render to occur during the next animation frame.
@@ -418,12 +415,7 @@ impl VdomWeak {
418 /// `render` instead.
415 /// `render` instead.
419 pub fn schedule_render(&self) {
416 pub fn schedule_render(&self) {
420 debug!("VdomWeak::schedule_render");
417 debug!("VdomWeak::schedule_render");
421−
422− let future = self.render();
423−
424− wasm_bindgen_futures::spawn_local(async move {
418+ wasm_bindgen_futures::spawn_local(self.render().map_err(|_| ()));
425− let _ = future.await;
426− });
427 }
419 }
428
420
429 /// Schedule a render to occur during the next animation frame and return a
421 /// Schedule a render to occur during the next animation frame and return a
@@ -431,46 +423,41 @@ impl VdomWeak {
431 ///
423 ///
432 /// If you don't want to do more things after the render completes, then use
424 /// If you don't want to do more things after the render completes, then use
433 /// `schedule_render` instead of `render`.
425 /// `schedule_render` instead of `render`.
434− pub fn render(&self) -> impl Future<Output = Result<(), VdomDroppedError>> {
426+ pub fn render(&self) -> impl Future<Item = (), Error = VdomDroppedError> {
435− let inner = self.inner.upgrade();
427+ futures::future::ok(self.inner.upgrade())
436−
428+ .and_then(|inner| inner.ok_or(()))
437− async move {
438− let inner = inner.ok_or(VdomDroppedError {})?;
429+ .map_err(|_| VdomDroppedError {})
439−
430+ .and_then(|inner| {
440− let promise = inner.shared.render_scheduled.take().unwrap_or_else(|| {
431+ let promise = inner.shared.render_scheduled.take().unwrap_or_else(|| {
441− js_sys::Promise::new(&mut |resolve, reject| {
432+ js_sys::Promise::new(&mut |resolve, reject| {
442− let vdom = VdomWeak {
433+ let vdom = VdomWeak {
443− inner: Rc::downgrade(&inner),
434+ inner: Rc::downgrade(&inner),
444− };
435+ };
445−
446− with_animation_frame(move || match vdom.inner.upgrade() {
436+ with_animation_frame(move || match vdom.inner.upgrade() {
447− None => {
437+ None => {
448− warn!("VdomWeak::render: vdom unmounted before we could render");
438+ warn!("VdomWeak::render: vdom unmounted before we could render");
449− let r = reject.call0(&JsValue::null());
439+ let r = reject.call0(&JsValue::null());
450− debug_assert!(r.is_ok());
440+ debug_assert!(r.is_ok());
451− }
441+ }
452− Some(inner) => {
442+ Some(inner) => {
453− let mut exclusive = inner.exclusive.borrow_mut();
443+ let mut exclusive = inner.exclusive.borrow_mut();
454− exclusive.render();
444+ exclusive.render();
455−
445+
456− // We did the render, so take the promise away
446+ // We did the render, so take the promise away
457− // and let future `render` calls request new
447+ // and let future `render` calls request new
458− // animation frames.
448+ // animation frames.
459− let _ = inner.shared.render_scheduled.take();
449+ let _ = inner.shared.render_scheduled.take();
460−
450+
461− let r = resolve.call0(&JsValue::null());
451+ let r = resolve.call0(&JsValue::null());
462− debug_assert!(r.is_ok());
452+ debug_assert!(r.is_ok());
463− }
453+ }
464− });
454+ });
465− })
455+ })
466− });
456+ });
467−
468− inner.shared.render_scheduled.set(Some(promise.clone()));
457+ inner.shared.render_scheduled.set(Some(promise.clone()));
469−
470− JsFuture::from(promise)
458+ JsFuture::from(promise)
471− .await
472− .map(drop)
459+ .map(|_| ())
473− .map_err(|_| VdomDroppedError {})
460+ .map_err(|_| VdomDroppedError {})
474− }
461+ })
475 }
462 }
476}
463}
tests/web/cached.jsdeleted−11
@@ -1,11 +0,0 @@
1−let cloneNodeCount = 0;
2−
3−const origCloneNode = Node.prototype.cloneNode;
4−Node.prototype.cloneNode = function (...args) {
5− cloneNodeCount += 1;
6− return origCloneNode.apply(this, args);
7−};
8−
9−export function getCloneNodeCount() {
10− return cloneNodeCount;
11−}
tests/web/cached.rs+48−103
@@ -1,11 +1,11 @@
1use super::{assert_rendered, before_after, create_element, RenderFn};
1use super::{assert_rendered, before_after, create_element, RenderFn};
2−use dodrio::{builder::*, bumpalo, Cached, Node, Render, RenderContext, RootRender, Vdom};
2+use dodrio::{builder::*, bumpalo, Cached, Node, Render, RenderContext, Vdom};
3+use futures::prelude::*;
3use std::cell::Cell;
4use std::cell::Cell;
4use std::rc::Rc;
5use std::rc::Rc;
5−use wasm_bindgen::prelude::*;
6+use wasm_bindgen::*;
6use wasm_bindgen_test::*;
7use wasm_bindgen_test::*;
7
8
8−#[derive(Default)]
9pub struct CountRenders {
9pub struct CountRenders {
10 render_count: Cell<usize>,
10 render_count: Cell<usize>,
11}
11}
@@ -18,8 +18,8 @@ impl CountRenders {
18 }
18 }
19}
19}
20
20
21−impl<'a> Render<'a> for CountRenders {
21+impl Render for CountRenders {
22− fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
22+ fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
23 let count = self.render_count.get() + 1;
23 let count = self.render_count.get() + 1;
24 self.render_count.set(count);
24 self.render_count.set(count);
25
25
@@ -28,8 +28,8 @@ impl<'a> Render<'a> for CountRenders {
28 }
28 }
29}
29}
30
30
31−#[wasm_bindgen_test]
31+#[wasm_bindgen_test(async)]
32−async fn uses_cached_render() {
32+fn uses_cached_render() -> impl Future<Item = (), Error = JsValue> {
33 use dodrio::builder::*;
33 use dodrio::builder::*;
34
34
35 let cached = Cached::new(CountRenders::new());
35 let cached = Cached::new(CountRenders::new());
@@ -49,112 +49,57 @@ async fn uses_cached_render() {
49 let vdom6 = vdom0.clone();
49 let vdom6 = vdom0.clone();
50 let vdom7 = vdom0.clone();
50 let vdom7 = vdom0.clone();
51
51
52− // We render, populate the cache, and get "1".
53− vdom0.weak().render().await.unwrap();
54 vdom0
52 vdom0
55 .weak()
53 .weak()
54+ // We render, populate the cache, and get "1".
55+ .render()
56+ .and_then(move |_| {
56− .with_component(move |comp| {
57+ vdom0.weak().with_component(move |comp| {
57− let comp = comp.unwrap_mut::<Cached<CountRenders>>();
58+ let comp = comp.unwrap_mut::<Cached<CountRenders>>();
58− assert_eq!(comp.render_count.get(), 1);
59+ assert_eq!(comp.render_count.get(), 1);
59− assert_rendered(&container1, &RenderFn(|_| text("1")));
60+ assert_rendered(&container1, &RenderFn(|_| text("1")));
61+ })
60 })
62 })
61− .await
62− .unwrap();
63−
64− // We re-render, re-use the cached node, and get "1" again.
63+ // We re-render, re-use the cached node, and get "1" again.
65− vdom1.weak().render().await.unwrap();
64+ .and_then(move |_| vdom1.weak().render())
66− vdom2
65+ .and_then(move |_| {
67− .weak()
68− .with_component(move |comp| {
66+ vdom2.weak().with_component(move |comp| {
69− let comp = comp.unwrap_mut::<Cached<CountRenders>>();
67+ let comp = comp.unwrap_mut::<Cached<CountRenders>>();
70− assert_eq!(comp.render_count.get(), 1);
68+ assert_eq!(comp.render_count.get(), 1);
71− assert_rendered(&container2, &RenderFn(|_| text("1")));
69+ assert_rendered(&container2, &RenderFn(|_| text("1")));
70+ })
72 })
71 })
73− .await
74− .unwrap();
75−
76− // We invalidate the cache, re-render, re-populate the cache, and should now have "2".
72+ // We invalidate the cache, re-render, re-populate the cache, and should
77− vdom3
73+ // now have "2".
78− .weak()
74+ .and_then(move |_| {
79− .with_component(move |comp| {
75+ vdom3.weak().with_component(move |comp| {
80− let comp = comp.unwrap_mut::<Cached<CountRenders>>();
76+ let comp = comp.unwrap_mut::<Cached<CountRenders>>();
81− Cached::invalidate(comp);
77+ Cached::invalidate(comp);
78+ })
82 })
79 })
83− .await
84− .unwrap();
85− vdom4.weak().render().await.unwrap();
80+ .and_then(move |_| vdom4.weak().render())
86− vdom5
81+ .and_then(move |_| {
87− .weak()
88− .with_component(move |comp| {
82+ vdom5.weak().with_component(move |comp| {
89− let comp = comp.unwrap_mut::<Cached<CountRenders>>();
83+ let comp = comp.unwrap_mut::<Cached<CountRenders>>();
90− assert_eq!(comp.render_count.get(), 2);
84+ assert_eq!(comp.render_count.get(), 2);
91− assert_rendered(&container3, &RenderFn(|_| text("2")));
85+ assert_rendered(&container3, &RenderFn(|_| text("2")));
86+ })
92 })
87 })
93− .await
94− .unwrap();
95−
96− // We re-render, re-use the cached node, and get "2" again.
88+ // We re-render, re-use the cached node, and get "2" again.
97− vdom6.weak().render().await.unwrap();
89+ .and_then(move |_| vdom6.weak().render())
98− vdom7
90+ .and_then(move |_| {
99− .weak()
100− .with_component(move |comp| {
91+ vdom7.weak().with_component(move |comp| {
101− let comp = comp.unwrap_mut::<Cached<CountRenders>>();
92+ let comp = comp.unwrap_mut::<Cached<CountRenders>>();
102− assert_eq!(comp.render_count.get(), 2);
93+ assert_eq!(comp.render_count.get(), 2);
103− assert_rendered(&container4, &RenderFn(|_| text("2")));
94+ assert_rendered(&container4, &RenderFn(|_| text("2")));
95+ })
104 })
96 })
105− .await
97+ .map_err(|e| JsValue::from(e.to_string()))
106− .unwrap();
107−}
108−
109−#[wasm_bindgen(module = "/tests/web/cached.js")]
110−extern "C" {
111− #[wasm_bindgen(js_name = getCloneNodeCount)]
112− fn get_clone_node_count() -> u32;
113−}
114−
115−#[wasm_bindgen_test]
116−async fn creating_cached_nodes_uses_clone_node() {
117− use dodrio::builder::*;
118−
119− let container = create_element("div");
120−
121− // The initial vdom render should populate the cache and save a template.
122− let vdom0 = Rc::new(Vdom::new(&container, Cached::new(CountRenders::new())));
123− let vdom1 = vdom0.clone();
124− let _vdom2 = vdom0.clone();
125−
126− let clone_node_count_before = get_clone_node_count();
127−
128− // Render something entirely different...
129− vdom0
130− .weak()
131− .set_component(Box::new(RenderFn(|_| text("hi"))) as Box<dyn RootRender>)
132− .await
133− .unwrap();
134−
135− // Re-render our cached node. Since we are creating it from scratch,
136− // and already have a template from the earlier render, we should
137− // call `cloneNode` here.
138− vdom1
139− .weak()
140− .set_component(Box::new(Cached::new(CountRenders::new())) as Box<dyn RootRender>)
141− .await
142− .unwrap();
143−
144− let clone_node_count_after = get_clone_node_count();
145− assert_eq!(clone_node_count_after, clone_node_count_before + 1);
146}
98}
147
99
148struct Id(&'static str);
100struct Id(&'static str);
149−
150−impl Default for Id {
151− fn default() -> Id {
152− Id("")
153− }
154−}
155−
156−impl<'a> Render<'a> for Id {
101+impl Render for Id {
157− fn render(&self, _cx: &mut RenderContext<'a>) -> Node<'a> {
102+ fn render<'a>(&self, _cx: &mut RenderContext<'a>) -> Node<'a> {
158 text(self.0)
103 text(self.0)
159 }
104 }
160}
105}
tests/web/events.rs+73−56
@@ -1,6 +1,6 @@
1use super::create_element;
1use super::create_element;
2use dodrio::{Node, Render, RenderContext, Vdom};
2use dodrio::{Node, Render, RenderContext, Vdom};
3−use futures::future::{select, Either};
3+use futures::Future;
4use std::cell::{Cell, RefCell};
4use std::cell::{Cell, RefCell};
5use std::rc::Rc;
5use std::rc::Rc;
6use wasm_bindgen::prelude::*;
6use wasm_bindgen::prelude::*;
@@ -9,7 +9,7 @@ use wasm_bindgen_test::*;
9
9
10struct EventContainer {
10struct EventContainer {
11 event: &'static str,
11 event: &'static str,
12− on_event: Box<dyn FnMut()>,
12+ on_event: Box<FnMut()>,
13}
13}
14
14
15impl EventContainer {
15impl EventContainer {
@@ -24,8 +24,8 @@ impl EventContainer {
24 }
24 }
25}
25}
26
26
27−impl<'a> Render<'a> for EventContainer {
27+impl Render for EventContainer {
28− fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
28+ fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
29 use dodrio::builder::*;
29 use dodrio::builder::*;
30 div(&cx)
30 div(&cx)
31 .attr("id", "target")
31 .attr("id", "target")
@@ -44,14 +44,14 @@ fn target(container: &web_sys::Element) -> web_sys::HtmlElement {
44 .unchecked_into()
44 .unchecked_into()
45}
45}
46
46
47−#[wasm_bindgen_test]
47+#[wasm_bindgen_test(async)]
48−async fn click() {
48+fn click() -> impl Future<Item = (), Error = JsValue> {
49 let container = create_element("div");
49 let container = create_element("div");
50
50
51− let (sender, receiver) = futures::channel::oneshot::channel();
51+ let (sender, receiver) = futures::sync::oneshot::channel();
52 let mut sender = Some(sender);
52 let mut sender = Some(sender);
53
53
54− let _vdom = Vdom::new(
54+ let vdom = Vdom::new(
55 &container,
55 &container,
56 EventContainer::new("click", move || {
56 EventContainer::new("click", move || {
57 sender
57 sender
@@ -64,14 +64,18 @@ async fn click() {
64
64
65 target(&container).click();
65 target(&container).click();
66
66
67− receiver.await.unwrap();
67+ receiver
68+ .map(|_| {
69+ drop(vdom);
70+ })
71+ .map_err(|e| JsValue::from(e.to_string()))
68}
72}
69
73
70−#[wasm_bindgen_test]
74+#[wasm_bindgen_test(async)]
71−async fn updated_listener_is_called() {
75+fn updated_listener_is_called() -> impl Future<Item = (), Error = JsValue> {
72 let container = create_element("div");
76 let container = create_element("div");
73
77
74− let (first_sender, first_receiver) = futures::channel::oneshot::channel();
78+ let (first_sender, first_receiver) = futures::sync::oneshot::channel();
75 let mut first_sender = Some(first_sender);
79 let mut first_sender = Some(first_sender);
76
80
77 let vdom = Vdom::new(
81 let vdom = Vdom::new(
@@ -85,7 +89,7 @@ async fn updated_listener_is_called() {
85 }),
89 }),
86 );
90 );
87
91
88− let (second_sender, second_receiver) = futures::channel::oneshot::channel();
92+ let (second_sender, second_receiver) = futures::sync::oneshot::channel();
89 let mut second_sender = Some(second_sender);
93 let mut second_sender = Some(second_sender);
90
94
91 vdom.weak()
95 vdom.weak()
@@ -96,22 +100,25 @@ async fn updated_listener_is_called() {
96 .send("second")
100 .send("second")
97 .expect_throw("should not have dropped the receiver");
101 .expect_throw("should not have dropped the receiver");
98 })))
102 })))
99− .await
103+ .map_err(|e| JsValue::from(e.to_string()))
100− .unwrap();
104+ .and_then(move |_| {
101−
102− target(&container).click();
105+ target(&container).click();
103−
106+
107+ first_receiver
104− match select(first_receiver, second_receiver).await {
108+ .select(second_receiver)
105− Either::Left((Ok(_), _)) => panic!(),
109+ .map(|(which, _other)| which)
110+ .or_else(|(_error, other)| other)
111+ .map(|which| {
106− Either::Left((Err(_), second)) => assert_eq!(second.await, Ok("second")),
112+ assert_eq!(which, "second");
107− Either::Right((Ok(msg), _)) => assert_eq!(msg, "second"),
113+ drop(vdom);
108− Either::Right((Err(_), _)) => panic!(),
114+ })
115+ .map_err(|e| JsValue::from(e.to_string()))
109− }
116+ })
110}
117}
111
118
112struct ListensOnlyOnFirstRender {
119struct ListensOnlyOnFirstRender {
113 count: Cell<usize>,
120 count: Cell<usize>,
114− callback: Box<dyn FnMut()>,
121+ callback: Box<FnMut()>,
115}
122}
116
123
117impl ListensOnlyOnFirstRender {
124impl ListensOnlyOnFirstRender {
@@ -126,8 +133,8 @@ impl ListensOnlyOnFirstRender {
126 }
133 }
127}
134}
128
135
129−impl<'a> Render<'a> for ListensOnlyOnFirstRender {
136+impl Render for ListensOnlyOnFirstRender {
130− fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
137+ fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
131 use dodrio::builder::*;
138 use dodrio::builder::*;
132
139
133 let count = self.count.get();
140 let count = self.count.get();
@@ -143,11 +150,11 @@ impl<'a> Render<'a> for ListensOnlyOnFirstRender {
143 }
150 }
144}
151}
145
152
146−#[wasm_bindgen_test]
153+#[wasm_bindgen_test(async)]
147−async fn removed_listener_is_not_called() {
154+fn removed_listener_is_not_called() -> impl Future<Item = (), Error = JsValue> {
148 let container = create_element("div");
155 let container = create_element("div");
149
156
150− let (outer_sender, outer_receiver) = futures::channel::oneshot::channel();
157+ let (outer_sender, outer_receiver) = futures::sync::oneshot::channel();
151 let outer_sender = Rc::new(RefCell::new(Some(outer_sender)));
158 let outer_sender = Rc::new(RefCell::new(Some(outer_sender)));
152 let outer_listener = Closure::wrap(Box::new(move |_| {
159 let outer_listener = Closure::wrap(Box::new(move |_| {
153 outer_sender
160 outer_sender
@@ -156,13 +163,13 @@ async fn removed_listener_is_not_called() {
156 .expect_throw("should only invoke outer_listener once")
163 .expect_throw("should only invoke outer_listener once")
157 .send("outer")
164 .send("outer")
158 .expect_throw("should not have dropped receiver");
165 .expect_throw("should not have dropped receiver");
159− }) as Box<dyn FnMut(web_sys::Event)>);
166+ }) as Box<FnMut(web_sys::Event)>);
160
167
161 container
168 container
162 .add_event_listener_with_callback("click", outer_listener.as_ref().unchecked_ref())
169 .add_event_listener_with_callback("click", outer_listener.as_ref().unchecked_ref())
163 .unwrap();
170 .unwrap();
164
171
165− let (vdom_sender, vdom_receiver) = futures::channel::oneshot::channel();
172+ let (vdom_sender, vdom_receiver) = futures::sync::oneshot::channel();
166 let mut vdom_sender = Some(vdom_sender);
173 let mut vdom_sender = Some(vdom_sender);
167
174
168 // Render a vdom with a listener into container.
175 // Render a vdom with a listener into container.
@@ -177,26 +184,33 @@ async fn removed_listener_is_not_called() {
177 }),
184 }),
178 );
185 );
179
186
187+ vdom.weak()
180− // Re-render, so we aren't listening anymore.
188+ // Re-render, so we aren't listening anymore.
181− vdom.weak().render().await.unwrap();
189+ .render()
182−
190+ .map_err(|e| JsValue::from(e.to_string()))
191+ .and_then(move |_| {
183− target(&container).click();
192+ target(&container).click();
184−
193+
185− // We should get our container's event handler fired, and not the unmounted
194+ // We should get our container's event handler fired, and not the unmounted
186− // vdom's event handler.
195+ // vdom's event handler.
196+ outer_receiver
187− match select(outer_receiver, vdom_receiver).await {
197+ .select(vdom_receiver)
198+ .map(|(which, _other)| which)
199+ .or_else(|(_error, other)| other)
200+ .map(|which| {
188− Either::Left((Ok(msg), _)) => assert_eq!(msg, ("outer")),
201+ assert_eq!(which, "outer");
189− Either::Left((Err(_), _)) => panic!(),
202+ drop(outer_listener);
190− Either::Right((Ok(_), _)) => panic!(),
203+ drop(vdom)
191− Either::Right((Err(_), outer)) => assert_eq!(outer.await, Ok("outer")),
204+ })
205+ .map_err(|e| JsValue::from(e.to_string()))
192− }
206+ })
193}
207}
194
208
195−#[wasm_bindgen_test]
209+#[wasm_bindgen_test(async)]
196−async fn event_does_not_fire_after_unmounting() {
210+fn event_does_not_fire_after_unmounting() -> impl Future<Item = (), Error = JsValue> {
197 let container = create_element("div");
211 let container = create_element("div");
198
212
199− let (outer_sender, outer_receiver) = futures::channel::oneshot::channel();
213+ let (outer_sender, outer_receiver) = futures::sync::oneshot::channel();
200 let outer_sender = Rc::new(RefCell::new(Some(outer_sender)));
214 let outer_sender = Rc::new(RefCell::new(Some(outer_sender)));
201 let outer_listener = Closure::wrap(Box::new(move |_| {
215 let outer_listener = Closure::wrap(Box::new(move |_| {
202 outer_sender
216 outer_sender
@@ -205,13 +219,13 @@ async fn event_does_not_fire_after_unmounting() {
205 .expect_throw("should only invoke outer_listener once")
219 .expect_throw("should only invoke outer_listener once")
206 .send("outer")
220 .send("outer")
207 .expect_throw("should not have dropped receiver");
221 .expect_throw("should not have dropped receiver");
208− }) as Box<dyn FnMut(web_sys::Event)>);
222+ }) as Box<FnMut(web_sys::Event)>);
209
223
210 container
224 container
211 .add_event_listener_with_callback("click", outer_listener.as_ref().unchecked_ref())
225 .add_event_listener_with_callback("click", outer_listener.as_ref().unchecked_ref())
212 .unwrap();
226 .unwrap();
213
227
214− let (vdom_sender, vdom_receiver) = futures::channel::oneshot::channel();
228+ let (vdom_sender, vdom_receiver) = futures::sync::oneshot::channel();
215 let mut vdom_sender = Some(vdom_sender);
229 let mut vdom_sender = Some(vdom_sender);
216
230
217 // Render a vdom with a listener into container.
231 // Render a vdom with a listener into container.
@@ -241,10 +255,13 @@ async fn event_does_not_fire_after_unmounting() {
241
255
242 // We should get our container's event handler fired, and not the unmounted
256 // We should get our container's event handler fired, and not the unmounted
243 // vdom's event handler.
257 // vdom's event handler.
244− match select(outer_receiver, vdom_receiver).await {
258+ outer_receiver
259+ .select(vdom_receiver)
260+ .map(|(which, _other)| which)
261+ .or_else(|(_error, other)| other)
262+ .map(|which| {
245− Either::Left((Ok(msg), _)) => assert_eq!(msg, ("outer")),
263+ assert_eq!(which, "outer");
246− Either::Left((Err(_), _)) => panic!(),
264+ drop(outer_listener);
247− Either::Right((Ok(_), _)) => panic!(),
248− Either::Right((Err(_), outer)) => assert_eq!(outer.await, Ok("outer")),
249− }
265+ })
266+ .map_err(|e| JsValue::from(e.to_string()))
250}
267}
tests/web/js_api.rs+37−30
@@ -1,7 +1,8 @@
1use super::{assert_rendered, create_element, RenderFn};
1use super::{assert_rendered, create_element, RenderFn};
2use dodrio::{builder::*, Node, Render, RenderContext, Vdom};
2use dodrio::{builder::*, Node, Render, RenderContext, Vdom};
3use dodrio_js_api::JsRender;
3use dodrio_js_api::JsRender;
4−use futures::channel::oneshot;
4+use futures::prelude::*;
5+use futures::sync::oneshot;
5use js_sys::Object;
6use js_sys::Object;
6use std::rc::Rc;
7use std::rc::Rc;
7use wasm_bindgen::prelude::*;
8use wasm_bindgen::prelude::*;
@@ -13,7 +14,7 @@ pub struct WrapJs {
13}
14}
14
15
15impl WrapJs {
16impl WrapJs {
16− pub fn new() -> (WrapJs, oneshot::Receiver<()>, Closure<dyn FnMut()>) {
17+ pub fn new() -> (WrapJs, oneshot::Receiver<()>, Closure<FnMut()>) {
17 let (sender, receiver) = oneshot::channel();
18 let (sender, receiver) = oneshot::channel();
18
19
19 let on_after_render = Closure::wrap(Box::new({
20 let on_after_render = Closure::wrap(Box::new({
@@ -25,7 +26,7 @@ impl WrapJs {
25 .send(())
26 .send(())
26 .expect_throw("receiver should not have been dropped");
27 .expect_throw("receiver should not have been dropped");
27 }
28 }
28− }) as Box<dyn FnMut()>);
29+ }) as Box<FnMut()>);
29
30
30 let component = WrapJs {
31 let component = WrapJs {
31 inner: JsRender::new(JsComponent::new(&on_after_render)),
32 inner: JsRender::new(JsComponent::new(&on_after_render)),
@@ -35,8 +36,8 @@ impl WrapJs {
35 }
36 }
36}
37}
37
38
38−impl<'a> Render<'a> for WrapJs {
39+impl Render for WrapJs {
39− fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
40+ fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
40 div(&cx)
41 div(&cx)
41 .attr("class", "wrap-js")
42 .attr("class", "wrap-js")
42 .children([self.inner.render(cx)])
43 .children([self.inner.render(cx)])
@@ -51,7 +52,7 @@ extern "C" {
51 type JsComponent;
52 type JsComponent;
52
53
53 #[wasm_bindgen(constructor)]
54 #[wasm_bindgen(constructor)]
54− fn new(on_after_render: &Closure<dyn FnMut()>) -> JsComponent;
55+ fn new(on_after_render: &Closure<FnMut()>) -> JsComponent;
55}
56}
56
57
57fn eval_js_rendering_component() {
58fn eval_js_rendering_component() {
@@ -95,14 +96,14 @@ fn eval_js_rendering_component() {
95 });
96 });
96}
97}
97
98
98−#[wasm_bindgen_test]
99+#[wasm_bindgen_test(async)]
99−async fn can_use_js_rendering_components() {
100+fn can_use_js_rendering_components() -> impl Future<Item = (), Error = JsValue> {
100 eval_js_rendering_component();
101 eval_js_rendering_component();
101
102
102 let container = create_element("div");
103 let container = create_element("div");
103− let (component, receiver, _closure) = WrapJs::new();
104+ let (component, receiver, closure) = WrapJs::new();
104− let _vdom = Rc::new(Vdom::new(&container, component));
105
105
106+ let vdom = Rc::new(Vdom::new(&container, component));
106 assert_rendered(
107 assert_rendered(
107 &container,
108 &container,
108 &RenderFn(|cx| {
109 &RenderFn(|cx| {
@@ -130,24 +131,30 @@ async fn can_use_js_rendering_components() {
130 .expect_throw("should be an `HTMLElement` object")
131 .expect_throw("should be an `HTMLElement` object")
131 .click();
132 .click();
132
133
133− receiver.await.unwrap();
134+ receiver
134−
135+ .map(move |_| {
135− assert_rendered(
136+ assert_rendered(
136− &container,
137+ &container,
137− &RenderFn(|cx| {
138+ &RenderFn(|cx| {
138− div(&cx)
139+ div(&cx)
139− .attr("class", "wrap-js")
140+ .attr("class", "wrap-js")
140− .children([span(&cx)
141+ .children([span(&cx)
141− .attr("class", "js-component")
142+ .attr("class", "js-component")
142− .children([
143+ .children([
143− text("Here is some plain text"),
144+ text("Here is some plain text"),
144− b(&cx)
145+ b(&cx)
145− .children([text("...and here is some bold text")])
146+ .children([text("...and here is some bold text")])
146− .finish(),
147+ .finish(),
147− text("1"),
148+ text("1"),
148− ])
149+ ])
149− .finish()])
150+ .finish()])
150− .finish()
151+ .finish()
151− }),
152+ }),
152− );
153+ );
154+
155+ drop(vdom);
156+ drop(container);
157+ drop(closure);
158+ })
159+ .map_err(|e| e.to_string().into())
153}
160}
tests/web/keyed.rs+19−18
@@ -1,5 +1,6 @@
1use crate::{assert_rendered, create_element};
1use crate::{assert_rendered, create_element};
2use dodrio::{builder::*, bumpalo, Node, Render, RenderContext, Vdom};
2use dodrio::{builder::*, bumpalo, Node, Render, RenderContext, Vdom};
3+use futures::Future;
3use log::*;
4use log::*;
4use std::rc::Rc;
5use std::rc::Rc;
5use wasm_bindgen::prelude::*;
6use wasm_bindgen::prelude::*;
@@ -7,8 +8,8 @@ use wasm_bindgen_test::*;
7
8
8struct Keyed(u16);
9struct Keyed(u16);
9
10
10−impl<'a> Render<'a> for Keyed {
11+impl Render for Keyed {
11− fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
12+ fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
12 let key = bumpalo::format!(in cx.bump, "{}", self.0).into_bump_str();
13 let key = bumpalo::format!(in cx.bump, "{}", self.0).into_bump_str();
13 div(&cx)
14 div(&cx)
14 .attr("class", "keyed")
15 .attr("class", "keyed")
@@ -31,10 +32,13 @@ where
31 parent.finish()
32 parent.finish()
32}
33}
33
34
34−async fn assert_keyed<Before, After>(before: Before, after: After) -> Result<(), JsValue>
35+fn assert_keyed<Before, After>(
36+ before: Before,
37+ after: After,
38+) -> impl Future<Item = (), Error = JsValue>
35where
39where
36− Before: 'static + for<'a> Render<'a>,
40+ Before: 'static + Render,
37− After: 'static + for<'a> Render<'a>,
41+ After: 'static + Render,
38{
42{
39 #[wasm_bindgen(module = "/tests/web/keyed.js")]
43 #[wasm_bindgen(module = "/tests/web/keyed.js")]
40 extern "C" {
44 extern "C" {
@@ -52,7 +56,7 @@ where
52
56
53 debug!("====== Rendering the *before* DOM into the physical DOM ======");
57 debug!("====== Rendering the *before* DOM into the physical DOM ======");
54 let vdom1 = Rc::new(Vdom::new(&container, before.clone()));
58 let vdom1 = Rc::new(Vdom::new(&container, before.clone()));
55− let _vdom2 = vdom1.clone();
59+ let vdom2 = vdom1.clone();
56 let saved = save_keyed_elements(&container);
60 let saved = save_keyed_elements(&container);
57
61
58 debug!("====== Checking the *before* DOM against the physical DOM ======");
62 debug!("====== Checking the *before* DOM against the physical DOM ======");
@@ -61,14 +65,13 @@ where
61 debug!("====== Rendering the *after* DOM into the physical DOM ======");
65 debug!("====== Rendering the *after* DOM into the physical DOM ======");
62 let weak = vdom1.weak();
66 let weak = vdom1.weak();
63 weak.set_component(Box::new(after.clone()))
67 weak.set_component(Box::new(after.clone()))
64− .await
68+ .map(move |_| {
65− .map_err(|e| e.to_string())?;
66−
67− debug!("====== Checking the *after* DOM against the physical DOM ======");
69+ debug!("====== Checking the *after* DOM against the physical DOM ======");
68− assert_rendered(&container, &after);
70+ assert_rendered(&container, &after);
69− check_keyed_elements(&container, saved);
71+ check_keyed_elements(&container, saved);
70−
72+ drop(vdom2);
71− Ok(())
73+ })
74+ .map_err(|e| JsValue::from(e.to_string()))
72}
75}
73
76
74macro_rules! keyed_tests {
77macro_rules! keyed_tests {
@@ -83,16 +86,14 @@ macro_rules! keyed_tests {
83 }
86 }
84 )* ) => {
87 )* ) => {
85 $(
88 $(
86− #[wasm_bindgen_test]
89+ #[wasm_bindgen_test(async)]
87− async fn $name() {
90+ fn $name() -> impl Future<Item = (), Error = wasm_bindgen::JsValue> {
88 use crate::RenderFn;
91 use crate::RenderFn;
89 log::debug!("############### {} ###############", stringify!($name));
92 log::debug!("############### {} ###############", stringify!($name));
90 assert_keyed(
93 assert_keyed(
91 RenderFn(|$before_cx| { $( $before )* }),
94 RenderFn(|$before_cx| { $( $before )* }),
92 RenderFn(|$after_cx| { $( $after )* }),
95 RenderFn(|$after_cx| { $( $after )* }),
93 )
96 )
94− .await
95− .unwrap()
96 }
97 }
97 )*
98 )*
98 }
99 }
tests/web/main.rs+19−23
@@ -6,7 +6,7 @@ use bumpalo::Bump;
6use dodrio::{
6use dodrio::{
7 Attribute, CachedSet, ElementNode, Node, NodeKind, Render, RenderContext, TextNode, Vdom,
7 Attribute, CachedSet, ElementNode, Node, NodeKind, Render, RenderContext, TextNode, Vdom,
8};
8};
9−use fxhash::FxHashMap;
9+use futures::prelude::*;
10use log::*;
10use log::*;
11use std::cell::RefCell;
11use std::cell::RefCell;
12use std::rc::Rc;
12use std::rc::Rc;
@@ -50,13 +50,12 @@ pub fn init_logging() {
50
50
51/// Assert that the `container` contains the physical DOM tree that matches
51/// Assert that the `container` contains the physical DOM tree that matches
52/// `r`'s rendered virtual DOM.
52/// `r`'s rendered virtual DOM.
53−pub fn assert_rendered<R: for<'a> Render<'a>>(container: &web_sys::Element, r: &R) {
53+pub fn assert_rendered<R: Render>(container: &web_sys::Element, r: &R) {
54 init_logging();
54 init_logging();
55
55
56 let cached_set = &RefCell::new(CachedSet::default());
56 let cached_set = &RefCell::new(CachedSet::default());
57 let bump = &Bump::new();
57 let bump = &Bump::new();
58− let templates = &mut FxHashMap::default();
59− let cx = &mut RenderContext::new(bump, cached_set, templates);
58+ let cx = &mut RenderContext::new(bump, cached_set);
60 let node = r.render(cx);
59 let node = r.render(cx);
61 let child = container
60 let child = container
62 .first_child()
61 .first_child()
@@ -112,7 +111,7 @@ pub fn assert_rendered<R: for<'a> Render<'a>>(container: &web_sys::Element, r: &
112 }
111 }
113 }
112 }
114 NodeKind::Cached(ref c) => {
113 NodeKind::Cached(ref c) => {
115− let (expected, _template) = cached_set.get(c.id);
114+ let expected = cached_set.get(c.id);
116 check_node(cached_set, actual, &expected);
115 check_node(cached_set, actual, &expected);
117 }
116 }
118 }
117 }
@@ -155,11 +154,11 @@ pub struct RenderFn<F>(F)
155where
154where
156 F: for<'a> Fn(&mut RenderContext<'a>) -> Node<'a>;
155 F: for<'a> Fn(&mut RenderContext<'a>) -> Node<'a>;
157
156
158−impl<'a, F> Render<'a> for RenderFn<F>
157+impl<F> Render for RenderFn<F>
159where
158where
160− F: for<'b> Fn(&mut RenderContext<'b>) -> Node<'b>,
159+ F: for<'a> Fn(&mut RenderContext<'a>) -> Node<'a>,
161{
160{
162− fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
161+ fn render<'a>(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
163 (self.0)(cx)
162 (self.0)(cx)
164 }
163 }
165}
164}
@@ -167,10 +166,10 @@ where
167/// Assert that if we start by rendering the `before` virtual DOM tree into a
166/// Assert that if we start by rendering the `before` virtual DOM tree into a
168/// physical DOM tree, and then diff it with the `after` virtual DOM tree, then
167/// physical DOM tree, and then diff it with the `after` virtual DOM tree, then
169/// the physical DOM tree correctly matches `after`.
168/// the physical DOM tree correctly matches `after`.
170−pub async fn assert_before_after<R, S>(before: R, after: S) -> Result<(), JsValue>
169+pub fn assert_before_after<R, S>(before: R, after: S) -> impl Future<Item = (), Error = JsValue>
171where
170where
172− R: 'static + for<'a> Render<'a>,
171+ R: 'static + Render,
173− S: 'static + for<'a> Render<'a>,
172+ S: 'static + Render,
174{
173{
175 let container = create_element("div");
174 let container = create_element("div");
176
175
@@ -179,7 +178,7 @@ where
179
178
180 debug!("====== Rendering the *before* DOM into the physical DOM ======");
179 debug!("====== Rendering the *before* DOM into the physical DOM ======");
181 let vdom1 = Rc::new(Vdom::new(&container, before.clone()));
180 let vdom1 = Rc::new(Vdom::new(&container, before.clone()));
182− let _vdom2 = vdom1.clone();
181+ let vdom2 = vdom1.clone();
183
182
184 debug!("====== Checking the *before* DOM against the physical DOM ======");
183 debug!("====== Checking the *before* DOM against the physical DOM ======");
185 assert_rendered(&container, &before);
184 assert_rendered(&container, &before);
@@ -187,13 +186,12 @@ where
187 debug!("====== Rendering the *after* DOM into the physical DOM ======");
186 debug!("====== Rendering the *after* DOM into the physical DOM ======");
188 let weak = vdom1.weak();
187 let weak = vdom1.weak();
189 weak.set_component(Box::new(after.clone()))
188 weak.set_component(Box::new(after.clone()))
190− .await
189+ .map(move |_| {
191− .map_err(|e| e.to_string())?;
192−
193− debug!("====== Checking the *after* DOM against the physical DOM ======");
190+ debug!("====== Checking the *after* DOM against the physical DOM ======");
194− assert_rendered(&container, &after);
191+ assert_rendered(&container, &after);
195−
192+ drop(vdom2);
196− Ok(())
193+ })
194+ .map_err(|e| JsValue::from(e.to_string()))
197}
195}
198
196
199/// A helper macro for declaring a bunch of `assert_before_after` tests.
197/// A helper macro for declaring a bunch of `assert_before_after` tests.
@@ -210,16 +208,14 @@ macro_rules! before_after {
210 }
208 }
211 )* ) => {
209 )* ) => {
212 $(
210 $(
213− #[wasm_bindgen_test]
211+ #[wasm_bindgen_test(async)]
214− async fn $name() {
212+ fn $name() -> impl Future<Item = (), Error = wasm_bindgen::JsValue> {
215 use crate::{assert_before_after, RenderFn};
213 use crate::{assert_before_after, RenderFn};
216 log::debug!("############### {} ###############", stringify!($name));
214 log::debug!("############### {} ###############", stringify!($name));
217 assert_before_after(
215 assert_before_after(
218 RenderFn(|$before_bump| { $( $before )* }),
216 RenderFn(|$before_bump| { $( $before )* }),
219 RenderFn(|$after_bump| { $( $after )* })
217 RenderFn(|$after_bump| { $( $after )* })
220 )
218 )
221− .await
222− .unwrap()
223 }
219 }
224 )*
220 )*
225 }
221 }
tests/web/render.rs+2−89
@@ -1,7 +1,7 @@
1use super::{assert_rendered, before_after, create_element, RenderFn};
1use super::{assert_rendered, before_after, create_element, RenderFn};
2−use dodrio::{builder::*, bumpalo::collections::String, Node, Render, RenderContext, Vdom};
2+use dodrio::{builder::*, Vdom};
3+use futures::prelude::*;
3use std::rc::Rc;
4use std::rc::Rc;
4−use wasm_bindgen::{ JsCast};
5use wasm_bindgen_test::*;
5use wasm_bindgen_test::*;
6
6
7#[wasm_bindgen_test]
7#[wasm_bindgen_test]
@@ -35,93 +35,6 @@ fn container_is_emptied_upon_drop() {
35 assert!(container.first_child().is_none());
35 assert!(container.first_child().is_none());
36}
36}
37
37
38−/// Renders a child with a lifetime scoped to the RenderContext bump arena.
39−#[wasm_bindgen_test]
40−fn render_bump_scoped_node() {
41− struct Child<'a> {
42− name: &'a str,
43− }
44−
45− impl<'a> Render<'a> for Child<'a> {
46− fn render(&self, _cx: &mut RenderContext<'a>) -> Node<'a> {
47− text(self.name)
48− }
49− }
50−
51− struct Parent;
52−
53− impl<'a> Render<'a> for Parent {
54− fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
55− let child_name = String::from_str_in("child", cx.bump).into_bump_str();
56−
57− div(&cx)
58− .children([Child { name: child_name }.render(cx)])
59− .finish()
60− }
61− }
62−
63− let parent = Rc::new(RenderFn(|cx| {
64− Parent.render(cx)
65− }));
66−
67− let container = create_element("div");
68− let _vdom = Vdom::new(&container, parent.clone());
69−
70− assert_rendered(&container, &parent);
71−}
72−
73−/// Originally, dodrio would use the className property for SVGs.
74−///
75−/// This is problematic because when SVG elements are created, the className is flagged as a read
76−/// only property, so setting it causes an exception to be thrown. Here's an example of how this
77−/// happens:
78−///
79−/// let elem = web_sys::window()
80−/// .unwrap()
81−/// .document()
82−/// .unwrap()
83−/// .create_element_ns(Some("http://www.w3.org/2000/svg"), "svg")
84−/// .unwrap();
85−///
86−/// elem.set_class_name("does-not-work");
87−///
88−/// -----------------------------------------------------------------------------------------------
89−///
90−/// wasm-bindgen: imported JS function that was not marked as `catch` threw an error:
91−/// setting getter-only property "className"
92−///
93−/// -----------------------------------------------------------------------------------------------
94−///
95−/// Now, dodrio passes the 'class' attribute of all namespaced elements into set_attribute. This
96−/// satisfies the restrictions on SVG and keeps the optimized path for non-namespaced elements
97−#[wasm_bindgen_test(async)]
98−async fn test_svg_set_class() {
99− let container = create_element("div");
100−
101−
102− let valid_svg = Rc::new(RenderFn(|cx| {
103− ElementBuilder::new(cx.bump, "svg")
104− .namespace(Some("http://www.w3.org/2000/svg"))
105− .attr("class", "works")
106− .finish()
107− }));
108−
109− let vdom = Vdom::new(&container, valid_svg.clone());
110− let weak = vdom.weak();
111−
112− weak.render().await.unwrap();
113−
114− assert_eq!(
115− "works",
116− container.first_child()
117− .expect("unable to get svg")
118− .dyn_ref::<web_sys::Element>()
119− .expect("svg should be an element")
120− .get_attribute("class")
121− .expect("unable to get 'class' of svg")
122− );
123−}
124−
125before_after! {
38before_after! {
126 same_text {
39 same_text {
127 before(_cx) {
40 before(_cx) {