OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library barback.asset_node; | 5 library barback.asset_node; |
6 | 6 |
7 import 'dart:async'; | 7 import 'dart:async'; |
8 | 8 |
9 import 'asset.dart'; | 9 import 'asset.dart'; |
10 import 'asset_id.dart'; | 10 import 'asset_id.dart'; |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
43 /// The current state of the asset node. | 43 /// The current state of the asset node. |
44 AssetState get state => _state; | 44 AssetState get state => _state; |
45 AssetState _state; | 45 AssetState _state; |
46 | 46 |
47 /// The concrete asset that this node represents. | 47 /// The concrete asset that this node represents. |
48 /// | 48 /// |
49 /// This is null unless [state] is [AssetState.AVAILABLE]. | 49 /// This is null unless [state] is [AssetState.AVAILABLE]. |
50 Asset get asset => _asset; | 50 Asset get asset => _asset; |
51 Asset _asset; | 51 Asset _asset; |
52 | 52 |
| 53 /// The callback to be called to notify this asset node's creator that the |
| 54 /// concrete asset should be generated. |
| 55 /// |
| 56 /// This is null for non-lazy asset nodes (see [AssetNodeController.lazy]). |
| 57 /// Once this is called, it's set to null and [this] is no longer considered |
| 58 /// lazy. |
| 59 Function _lazyCallback; |
| 60 |
53 /// A broadcast stream that emits an event whenever the node changes state. | 61 /// A broadcast stream that emits an event whenever the node changes state. |
54 /// | 62 /// |
55 /// This stream is synchronous to ensure that when a source asset is modified | 63 /// This stream is synchronous to ensure that when a source asset is modified |
56 /// or removed, the appropriate portion of the asset graph is dirtied before | 64 /// or removed, the appropriate portion of the asset graph is dirtied before |
57 /// any [Barback.getAssetById] calls emit newly-incorrect values. | 65 /// any [Barback.getAssetById] calls emit newly-incorrect values. |
58 Stream<AssetState> get onStateChange => _stateChangeController.stream; | 66 Stream<AssetState> get onStateChange => _stateChangeController.stream; |
59 | 67 |
60 /// This is synchronous so that a source being updated will always be | 68 /// This is synchronous so that a source being updated will always be |
61 /// propagated through the build graph before anything that depends on it is | 69 /// propagated through the build graph before anything that depends on it is |
62 /// requested. | 70 /// requested. |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
131 } | 139 } |
132 | 140 |
133 AssetNode._(this.id, this._transform, this._origin) | 141 AssetNode._(this.id, this._transform, this._origin) |
134 : _state = AssetState.DIRTY; | 142 : _state = AssetState.DIRTY; |
135 | 143 |
136 AssetNode._available(Asset asset, this._transform, this._origin) | 144 AssetNode._available(Asset asset, this._transform, this._origin) |
137 : id = asset.id, | 145 : id = asset.id, |
138 _asset = asset, | 146 _asset = asset, |
139 _state = AssetState.AVAILABLE; | 147 _state = AssetState.AVAILABLE; |
140 | 148 |
141 String toString() => "$state asset $id"; | 149 AssetNode._lazy(this.id, this._transform, this._origin, this._lazyCallback) |
| 150 : _state = AssetState.DIRTY; |
| 151 |
| 152 /// If [this] is lazy, force it to generate a concrete asset; otherwise, do |
| 153 /// nothing. |
| 154 /// |
| 155 /// See [AssetNodeController.lazy]. |
| 156 void force() { |
| 157 if (_origin != null) { |
| 158 _origin.force(); |
| 159 } else if (_lazyCallback != null) { |
| 160 _lazyCallback(); |
| 161 _lazyCallback = null; |
| 162 } |
| 163 } |
| 164 |
| 165 String toString() => |
| 166 "$state${_lazyCallback == null ? '' : ' lazy'} asset $id"; |
142 } | 167 } |
143 | 168 |
144 /// The controller for an [AssetNode]. | 169 /// The controller for an [AssetNode]. |
145 /// | 170 /// |
146 /// This controls which state the node is in. | 171 /// This controls which state the node is in. |
147 class AssetNodeController { | 172 class AssetNodeController { |
148 final AssetNode node; | 173 final AssetNode node; |
149 | 174 |
150 /// Creates a controller for a dirty node. | 175 /// Creates a controller for a dirty node. |
151 AssetNodeController(AssetId id, [TransformNode transform]) | 176 AssetNodeController(AssetId id, [TransformNode transform]) |
152 : node = new AssetNode._(id, transform, null); | 177 : node = new AssetNode._(id, transform, null); |
153 | 178 |
154 /// Creates a controller for an available node with the given concrete | 179 /// Creates a controller for an available node with the given concrete |
155 /// [asset]. | 180 /// [asset]. |
156 AssetNodeController.available(Asset asset, [TransformNode transform]) | 181 AssetNodeController.available(Asset asset, [TransformNode transform]) |
157 : node = new AssetNode._available(asset, transform, null); | 182 : node = new AssetNode._available(asset, transform, null); |
158 | 183 |
| 184 /// Creates a controller for a lazy node. |
| 185 /// |
| 186 /// For the most part, this node works like any other dirty node. However, the |
| 187 /// owner of its controller isn't expected to do the work to make it available |
| 188 /// as soon as possible like they would for a non-lazy node. Instead, when its |
| 189 /// value is needed, [callback] will fire to indicate that it should be made |
| 190 /// available as soon as possible. |
| 191 /// |
| 192 /// [callback] is guaranteed to only fire once. |
| 193 AssetNodeController.lazy(AssetId id, void callback(), |
| 194 [TransformNode transform]) |
| 195 : node = new AssetNode._lazy(id, transform, null, callback); |
| 196 |
159 /// Creates a controller for a node whose initial state matches the current | 197 /// Creates a controller for a node whose initial state matches the current |
160 /// state of [node]. | 198 /// state of [node]. |
161 /// | 199 /// |
162 /// [AssetNode.origin] of the returned node will automatically be set to | 200 /// [AssetNode.origin] of the returned node will automatically be set to |
163 /// `node.origin`. | 201 /// `node.origin`. |
| 202 /// |
| 203 /// If [node] is lazy, the returned node will also be lazy. |
164 AssetNodeController.from(AssetNode node) | 204 AssetNodeController.from(AssetNode node) |
165 : node = new AssetNode._(node.id, node.transform, node.origin) { | 205 : node = new AssetNode._(node.id, node.transform, node.origin) { |
166 if (node.state.isAvailable) { | 206 if (node.state.isAvailable) { |
167 setAvailable(node.asset); | 207 setAvailable(node.asset); |
168 } else if (node.state.isRemoved) { | 208 } else if (node.state.isRemoved) { |
169 setRemoved(); | 209 setRemoved(); |
170 } | 210 } |
171 } | 211 } |
172 | 212 |
173 /// Marks the node as [AssetState.DIRTY]. | 213 /// Marks the node as [AssetState.DIRTY]. |
174 void setDirty() { | 214 void setDirty() { |
175 assert(node._state != AssetState.REMOVED); | 215 assert(node._state != AssetState.REMOVED); |
176 node._state = AssetState.DIRTY; | 216 node._state = AssetState.DIRTY; |
177 node._asset = null; | 217 node._asset = null; |
| 218 node._lazyCallback = null; |
178 node._stateChangeController.add(AssetState.DIRTY); | 219 node._stateChangeController.add(AssetState.DIRTY); |
179 } | 220 } |
180 | 221 |
181 /// Marks the node as [AssetState.REMOVED]. | 222 /// Marks the node as [AssetState.REMOVED]. |
182 /// | 223 /// |
183 /// Once a node is marked as removed, it can't be marked as any other state. | 224 /// Once a node is marked as removed, it can't be marked as any other state. |
184 /// If a new asset is created with the same id, it will get a new node. | 225 /// If a new asset is created with the same id, it will get a new node. |
185 void setRemoved() { | 226 void setRemoved() { |
186 assert(node._state != AssetState.REMOVED); | 227 assert(node._state != AssetState.REMOVED); |
187 node._state = AssetState.REMOVED; | 228 node._state = AssetState.REMOVED; |
188 node._asset = null; | 229 node._asset = null; |
| 230 node._lazyCallback = null; |
189 node._stateChangeController.add(AssetState.REMOVED); | 231 node._stateChangeController.add(AssetState.REMOVED); |
190 } | 232 } |
191 | 233 |
192 /// Marks the node as [AssetState.AVAILABLE] with the given concrete [asset]. | 234 /// Marks the node as [AssetState.AVAILABLE] with the given concrete [asset]. |
193 /// | 235 /// |
194 /// It's an error to mark an already-available node as available. It should be | 236 /// It's an error to mark an already-available node as available. It should be |
195 /// marked as dirty first. | 237 /// marked as dirty first. |
196 void setAvailable(Asset asset) { | 238 void setAvailable(Asset asset) { |
197 assert(asset.id == node.id); | 239 assert(asset.id == node.id); |
198 assert(node._state != AssetState.REMOVED); | 240 assert(node._state != AssetState.REMOVED); |
199 assert(node._state != AssetState.AVAILABLE); | 241 assert(node._state != AssetState.AVAILABLE); |
200 node._state = AssetState.AVAILABLE; | 242 node._state = AssetState.AVAILABLE; |
201 node._asset = asset; | 243 node._asset = asset; |
| 244 node._lazyCallback = null; |
202 node._stateChangeController.add(AssetState.AVAILABLE); | 245 node._stateChangeController.add(AssetState.AVAILABLE); |
203 } | 246 } |
204 | 247 |
| 248 /// Marks the node as [AssetState.DIRTY] and lazy. |
| 249 /// |
| 250 /// Lazy nodes aren't expected to have their values generated until needed. |
| 251 /// Once it's necessary, [callback] will be called. [callback] is guaranteed |
| 252 /// to be called only once. |
| 253 /// |
| 254 /// See also [AssetNodeController.lazy]. |
| 255 void setLazy(void callback()) { |
| 256 assert(node._state != AssetState.REMOVED); |
| 257 node._state = AssetState.DIRTY; |
| 258 node._asset = null; |
| 259 node._lazyCallback = callback; |
| 260 node._stateChangeController.add(AssetState.DIRTY); |
| 261 } |
| 262 |
205 String toString() => "controller for $node"; | 263 String toString() => "controller for $node"; |
206 } | 264 } |
207 | 265 |
208 // TODO(nweiz): add an error state. | 266 // TODO(nweiz): add an error state. |
209 /// An enum of states that an [AssetNode] can be in. | 267 /// An enum of states that an [AssetNode] can be in. |
210 class AssetState { | 268 class AssetState { |
211 /// The node has a concrete asset loaded, available, and up-to-date. The asset | 269 /// The node has a concrete asset loaded, available, and up-to-date. The asset |
212 /// is accessible via [AssetNode.asset]. An asset can only be marked available | 270 /// is accessible via [AssetNode.asset]. An asset can only be marked available |
213 /// again from the [AssetState.DIRTY] state. | 271 /// again from the [AssetState.DIRTY] state. |
214 static final AVAILABLE = const AssetState._("available"); | 272 static final AVAILABLE = const AssetState._("available"); |
(...skipping 14 matching lines...) Expand all Loading... |
229 | 287 |
230 /// Whether this state is [AssetState.DIRTY]. | 288 /// Whether this state is [AssetState.DIRTY]. |
231 bool get isDirty => this == AssetState.DIRTY; | 289 bool get isDirty => this == AssetState.DIRTY; |
232 | 290 |
233 final String name; | 291 final String name; |
234 | 292 |
235 const AssetState._(this.name); | 293 const AssetState._(this.name); |
236 | 294 |
237 String toString() => name; | 295 String toString() => name; |
238 } | 296 } |
OLD | NEW |