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.transform_node; | 5 library barback.transform_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 26 matching lines...) Expand all Loading... |
37 /// A string describing the location of [this] in the transformer graph. | 37 /// A string describing the location of [this] in the transformer graph. |
38 final String _location; | 38 final String _location; |
39 | 39 |
40 /// The subscription to [primary]'s [AssetNode.onStateChange] stream. | 40 /// The subscription to [primary]'s [AssetNode.onStateChange] stream. |
41 StreamSubscription _primarySubscription; | 41 StreamSubscription _primarySubscription; |
42 | 42 |
43 /// The subscription to [phase]'s [Phase.onAsset] stream. | 43 /// The subscription to [phase]'s [Phase.onAsset] stream. |
44 StreamSubscription<AssetNode> _phaseSubscription; | 44 StreamSubscription<AssetNode> _phaseSubscription; |
45 | 45 |
46 /// Whether [this] is dirty and still has more processing to do. | 46 /// Whether [this] is dirty and still has more processing to do. |
47 bool get isDirty => !_state.isDone; | 47 bool get isDirty => _state != _State.NOT_PRIMARY && _state != _State.APPLIED; |
48 | 48 |
49 /// Whether [transformer] is lazy and this transform has yet to be forced. | 49 /// Whether [transformer] is lazy and this transform has yet to be forced. |
50 bool _isLazy; | 50 bool _isLazy; |
51 | 51 |
52 /// The subscriptions to each input's [AssetNode.onStateChange] stream. | 52 /// The subscriptions to each input's [AssetNode.onStateChange] stream. |
53 final _inputSubscriptions = new Map<AssetId, StreamSubscription>(); | 53 final _inputSubscriptions = new Map<AssetId, StreamSubscription>(); |
54 | 54 |
55 /// The controllers for the asset nodes emitted by this node. | 55 /// The controllers for the asset nodes emitted by this node. |
56 final _outputControllers = new Map<AssetId, AssetNodeController>(); | 56 final _outputControllers = new Map<AssetId, AssetNodeController>(); |
57 | 57 |
(...skipping 25 matching lines...) Expand all Loading... |
83 | 83 |
84 /// A stream that emits an event whenever this transform logs an entry. | 84 /// A stream that emits an event whenever this transform logs an entry. |
85 /// | 85 /// |
86 /// This is synchronous because error logs can cause the transform to fail, so | 86 /// This is synchronous because error logs can cause the transform to fail, so |
87 /// we need to ensure that their processing isn't delayed until after the | 87 /// we need to ensure that their processing isn't delayed until after the |
88 /// transform or build has finished. | 88 /// transform or build has finished. |
89 Stream<LogEntry> get onLog => _onLogPool.stream; | 89 Stream<LogEntry> get onLog => _onLogPool.stream; |
90 final _onLogPool = new StreamPool<LogEntry>.broadcast(); | 90 final _onLogPool = new StreamPool<LogEntry>.broadcast(); |
91 | 91 |
92 /// The current state of [this]. | 92 /// The current state of [this]. |
93 var _state = _TransformNodeState.PROCESSING; | 93 var _state = _State.COMPUTING_IS_PRIMARY; |
94 | 94 |
95 /// Whether [this] has been marked as removed. | 95 /// Whether [this] has been marked as removed. |
96 bool get _isRemoved => _onAssetController.isClosed; | 96 bool get _isRemoved => _onAssetController.isClosed; |
97 | 97 |
98 /// Whether the most recent run of this transform has declared that it | 98 /// Whether the most recent run of this transform has declared that it |
99 /// consumes the primary input. | 99 /// consumes the primary input. |
100 /// | 100 /// |
101 /// Defaults to `false`. This is not meaningful unless [_state] is | 101 /// Defaults to `false`. This is not meaningful unless [_state] is |
102 /// [_TransformNodeState.APPLIED]. | 102 /// [_State.APPLIED]. |
103 bool _consumePrimary = false; | 103 bool _consumePrimary = false; |
104 | 104 |
105 TransformNode(this.phase, Transformer transformer, this.primary, | 105 TransformNode(this.phase, Transformer transformer, this.primary, |
106 this._location) | 106 this._location) |
107 : transformer = transformer, | 107 : transformer = transformer, |
108 _isLazy = transformer is LazyTransformer { | 108 _isLazy = transformer is LazyTransformer { |
109 _primarySubscription = primary.onStateChange.listen((state) { | 109 _primarySubscription = primary.onStateChange.listen((state) { |
110 if (state.isRemoved) { | 110 if (state.isRemoved) { |
111 remove(); | 111 remove(); |
112 } else { | 112 } else { |
113 _dirty(primaryChanged: true); | 113 _dirty(); |
114 } | 114 } |
115 }); | 115 }); |
116 | 116 |
117 _phaseSubscription = phase.previous.onAsset.listen((node) { | 117 _phaseSubscription = phase.previous.onAsset.listen((node) { |
118 if (_missingInputs.contains(node.id)) _dirty(primaryChanged: false); | 118 if (_missingInputs.contains(node.id)) _dirty(); |
119 }); | 119 }); |
120 | 120 |
121 _process(); | 121 syncFuture(() => transformer.isPrimary(primary.id)) |
| 122 .catchError((error, stackTrace) { |
| 123 if (_isRemoved) return false; |
| 124 |
| 125 // Catch all transformer errors and pipe them to the results stream. This |
| 126 // is so a broken transformer doesn't take down the whole graph. |
| 127 phase.cascade.reportError(_wrapException(error, stackTrace)); |
| 128 |
| 129 return false; |
| 130 }).then((isPrimary) { |
| 131 if (_isRemoved) return; |
| 132 if (isPrimary) { |
| 133 _apply(); |
| 134 return; |
| 135 } |
| 136 |
| 137 _emitPassThrough(); |
| 138 _state = _State.NOT_PRIMARY; |
| 139 _onDoneController.add(null); |
| 140 }); |
122 } | 141 } |
123 | 142 |
124 /// The [TransformInfo] describing this node. | 143 /// The [TransformInfo] describing this node. |
125 /// | 144 /// |
126 /// [TransformInfo] is the publicly-visible representation of a transform | 145 /// [TransformInfo] is the publicly-visible representation of a transform |
127 /// node. | 146 /// node. |
128 TransformInfo get info => new TransformInfo(transformer, primary.id); | 147 TransformInfo get info => new TransformInfo(transformer, primary.id); |
129 | 148 |
130 /// Marks this transform as removed. | 149 /// Marks this transform as removed. |
131 /// | 150 /// |
(...skipping 14 matching lines...) Expand all Loading... |
146 } | 165 } |
147 } | 166 } |
148 | 167 |
149 /// If [transformer] is lazy, ensures that its concrete outputs will be | 168 /// If [transformer] is lazy, ensures that its concrete outputs will be |
150 /// generated. | 169 /// generated. |
151 void force() { | 170 void force() { |
152 // TODO(nweiz): we might want to have a timeout after which, if the | 171 // TODO(nweiz): we might want to have a timeout after which, if the |
153 // transform's outputs have gone unused, we switch it back to lazy mode. | 172 // transform's outputs have gone unused, we switch it back to lazy mode. |
154 if (!_isLazy) return; | 173 if (!_isLazy) return; |
155 _isLazy = false; | 174 _isLazy = false; |
156 _dirty(primaryChanged: false); | 175 _dirty(); |
157 } | 176 } |
158 | 177 |
159 /// Marks this transform as dirty. | 178 /// Marks this transform as dirty. |
160 /// | 179 /// |
161 /// This causes all of the transform's outputs to be marked as dirty as well. | 180 /// This causes all of the transform's outputs to be marked as dirty as well. |
162 /// [primaryChanged] should be true if and only if [this] was set dirty | 181 void _dirty() { |
163 /// because [primary] changed. | 182 if (_state == _State.COMPUTING_IS_PRIMARY) return; |
164 void _dirty({bool primaryChanged: false}) { | 183 if (_state == _State.NOT_PRIMARY) { |
165 if (!primaryChanged && _state.isNotPrimary) return; | 184 _emitPassThrough(); |
| 185 return; |
| 186 } |
166 | 187 |
167 if (_passThroughController != null) _passThroughController.setDirty(); | 188 if (_passThroughController != null) _passThroughController.setDirty(); |
168 for (var controller in _outputControllers.values) { | 189 for (var controller in _outputControllers.values) { |
169 controller.setDirty(); | 190 controller.setDirty(); |
170 } | 191 } |
171 | 192 |
172 if (_state.isDone) { | 193 if (_state == _State.APPLIED) { |
173 if (primaryChanged) { | 194 _apply(); |
174 _process(); | 195 } else { |
175 } else { | 196 _state = _State.NEEDS_APPLY; |
176 _apply(); | |
177 } | |
178 } else if (primaryChanged) { | |
179 _state = _TransformNodeState.NEEDS_IS_PRIMARY; | |
180 } else if (!_state.needsIsPrimary) { | |
181 _state = _TransformNodeState.NEEDS_APPLY; | |
182 } | 197 } |
183 } | 198 } |
184 | 199 |
185 /// Determines whether [primary] is primary for [transformer], and if so runs | |
186 /// [transformer.apply]. | |
187 void _process() { | |
188 // Clear all the old input subscriptions. If an input is re-used, we'll | |
189 // re-subscribe. | |
190 _clearInputSubscriptions(); | |
191 _state = _TransformNodeState.PROCESSING; | |
192 primary.whenAvailable((_) { | |
193 _state = _TransformNodeState.PROCESSING; | |
194 return transformer.isPrimary(primary.asset); | |
195 }).catchError((error, stackTrace) { | |
196 // If the transform became dirty while processing, ignore any errors from | |
197 // it. | |
198 if (_state.needsIsPrimary || _isRemoved) return false; | |
199 | |
200 // Catch all transformer errors and pipe them to the results stream. This | |
201 // is so a broken transformer doesn't take down the whole graph. | |
202 phase.cascade.reportError(_wrapException(error, stackTrace)); | |
203 | |
204 return false; | |
205 }).then((isPrimary) { | |
206 if (_isRemoved) return; | |
207 if (_state.needsIsPrimary) { | |
208 _process(); | |
209 } else if (isPrimary) { | |
210 _apply(); | |
211 } else { | |
212 _clearOutputs(); | |
213 _emitPassThrough(); | |
214 _state = _TransformNodeState.NOT_PRIMARY; | |
215 _onDoneController.add(null); | |
216 } | |
217 }); | |
218 } | |
219 | |
220 /// Applies this transform. | 200 /// Applies this transform. |
221 void _apply() { | 201 void _apply() { |
222 assert(!_onAssetController.isClosed); | 202 assert(!_isRemoved); |
223 | 203 |
224 // Clear input subscriptions here as well as in [_process] because [_apply] | 204 // Clear input subscriptions here as well as in [_process] because [_apply] |
225 // may be restarted independently if only a secondary input changes. | 205 // may be restarted independently if only a secondary input changes. |
226 _clearInputSubscriptions(); | 206 _clearInputSubscriptions(); |
227 _state = _TransformNodeState.PROCESSING; | 207 _state = _State.APPLYING; |
228 primary.whenAvailable((_) { | 208 primary.whenAvailable((_) { |
229 if (_state.needsIsPrimary) return null; | 209 if (_isRemoved) return null; |
230 _state = _TransformNodeState.PROCESSING; | 210 _state = _State.APPLYING; |
231 // TODO(nweiz): If [transformer] is a [DeclaringTransformer] but not a | 211 // TODO(nweiz): If [transformer] is a [DeclaringTransformer] but not a |
232 // [LazyTransformer], we can get some mileage out of doing a declarative | 212 // [LazyTransformer], we can get some mileage out of doing a declaration |
233 // first so we know how to hook up the assets. | 213 // first so we know how to hook up the assets. |
234 if (_isLazy) return _declareLazy(); | 214 if (_isLazy) return _declareLazy(); |
235 return _applyImmediate(); | 215 return _applyImmediate(); |
236 }).catchError((error, stackTrace) { | 216 }).catchError((error, stackTrace) { |
237 // If the transform became dirty while processing, ignore any errors from | 217 // If the transform became dirty while processing, ignore any errors from |
238 // it. | 218 // it. |
239 if (!_state.isProcessing || _isRemoved) return false; | 219 if (_state == _State.NEEDS_APPLY || _isRemoved) return false; |
240 | 220 |
241 // Catch all transformer errors and pipe them to the results stream. This | 221 // Catch all transformer errors and pipe them to the results stream. This |
242 // is so a broken transformer doesn't take down the whole graph. | 222 // is so a broken transformer doesn't take down the whole graph. |
243 phase.cascade.reportError(_wrapException(error, stackTrace)); | 223 phase.cascade.reportError(_wrapException(error, stackTrace)); |
244 return true; | 224 return true; |
245 }).then((hadError) { | 225 }).then((hadError) { |
246 if (_isRemoved) return; | 226 if (_isRemoved) return; |
247 | 227 |
248 if (_state.needsIsPrimary) { | 228 if (_state == _State.NEEDS_APPLY) { |
249 _process(); | |
250 } else if (_state.needsApply) { | |
251 _apply(); | 229 _apply(); |
252 } else { | 230 return; |
253 assert(_state.isProcessing); | 231 } |
254 if (hadError) { | |
255 _clearOutputs(); | |
256 _dontEmitPassThrough(); | |
257 } | |
258 | 232 |
259 _state = _TransformNodeState.APPLIED; | 233 assert(_state == _State.APPLYING); |
260 _onDoneController.add(null); | 234 if (hadError) { |
| 235 _clearOutputs(); |
| 236 _dontEmitPassThrough(); |
261 } | 237 } |
| 238 |
| 239 _state = _State.APPLIED; |
| 240 _onDoneController.add(null); |
262 }); | 241 }); |
263 } | 242 } |
264 | 243 |
265 /// Gets the asset for an input [id]. | 244 /// Gets the asset for an input [id]. |
266 /// | 245 /// |
267 /// If an input with [id] cannot be found, throws an [AssetNotFoundException]. | 246 /// If an input with [id] cannot be found, throws an [AssetNotFoundException]. |
268 Future<Asset> getInput(AssetId id) { | 247 Future<Asset> getInput(AssetId id) { |
269 return phase.previous.getOutput(id).then((node) { | 248 return phase.previous.getOutput(id).then((node) { |
270 // Throw if the input isn't found. This ensures the transformer's apply | 249 // Throw if the input isn't found. This ensures the transformer's apply |
271 // is exited. We'll then catch this and report it through the proper | 250 // is exited. We'll then catch this and report it through the proper |
272 // results stream. | 251 // results stream. |
273 if (node == null) { | 252 if (node == null) { |
274 _missingInputs.add(id); | 253 _missingInputs.add(id); |
275 throw new AssetNotFoundException(id); | 254 throw new AssetNotFoundException(id); |
276 } | 255 } |
277 | 256 |
278 _inputSubscriptions.putIfAbsent(node.id, () { | 257 _inputSubscriptions.putIfAbsent(node.id, () { |
279 return node.onStateChange.listen((_) => _dirty(primaryChanged: false)); | 258 return node.onStateChange.listen((_) => _dirty()); |
280 }); | 259 }); |
281 | 260 |
282 return node.asset; | 261 return node.asset; |
283 }); | 262 }); |
284 } | 263 } |
285 | 264 |
286 /// Applies the transform so that it produces concrete (as opposed to lazy) | 265 /// Applies the transform so that it produces concrete (as opposed to lazy) |
287 /// outputs. | 266 /// outputs. |
288 /// | 267 /// |
289 /// Returns whether or not the transformer logged an error. | 268 /// Returns whether or not the transformer logged an error. |
290 Future<bool> _applyImmediate() { | 269 Future<bool> _applyImmediate() { |
291 var transformController = new TransformController(this); | 270 var transformController = new TransformController(this); |
292 _onLogPool.add(transformController.onLog); | 271 _onLogPool.add(transformController.onLog); |
293 | 272 |
294 return syncFuture(() { | 273 return syncFuture(() { |
295 return transformer.apply(transformController.transform); | 274 return transformer.apply(transformController.transform); |
296 }).then((_) { | 275 }).then((_) { |
297 if (!_state.isProcessing || _onAssetController.isClosed) return false; | 276 if (_state == _State.NEEDS_APPLY || _isRemoved) return false; |
298 if (transformController.loggedError) return true; | 277 if (transformController.loggedError) return true; |
299 | 278 |
300 _consumePrimary = transformController.consumePrimary; | 279 _consumePrimary = transformController.consumePrimary; |
301 | 280 |
302 var newOutputs = transformController.outputs; | 281 var newOutputs = transformController.outputs; |
303 // Any ids that are for a different package are invalid. | 282 // Any ids that are for a different package are invalid. |
304 var invalidIds = newOutputs | 283 var invalidIds = newOutputs |
305 .map((asset) => asset.id) | 284 .map((asset) => asset.id) |
306 .where((id) => id.package != phase.cascade.package) | 285 .where((id) => id.package != phase.cascade.package) |
307 .toSet(); | 286 .toSet(); |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
345 /// outputs. | 324 /// outputs. |
346 /// | 325 /// |
347 /// Returns whether or not the transformer logged an error. | 326 /// Returns whether or not the transformer logged an error. |
348 Future<bool> _declareLazy() { | 327 Future<bool> _declareLazy() { |
349 var transformController = new DeclaringTransformController(this); | 328 var transformController = new DeclaringTransformController(this); |
350 | 329 |
351 return syncFuture(() { | 330 return syncFuture(() { |
352 return (transformer as LazyTransformer) | 331 return (transformer as LazyTransformer) |
353 .declareOutputs(transformController.transform); | 332 .declareOutputs(transformController.transform); |
354 }).then((_) { | 333 }).then((_) { |
355 if (!_state.isProcessing || _onAssetController.isClosed) return false; | 334 if (_state == _State.NEEDS_APPLY || _isRemoved) return false; |
356 if (transformController.loggedError) return true; | 335 if (transformController.loggedError) return true; |
357 | 336 |
358 _consumePrimary = transformController.consumePrimary; | 337 _consumePrimary = transformController.consumePrimary; |
359 | 338 |
360 var newIds = transformController.outputIds; | 339 var newIds = transformController.outputIds; |
361 var invalidIds = | 340 var invalidIds = |
362 newIds.where((id) => id.package != phase.cascade.package).toSet(); | 341 newIds.where((id) => id.package != phase.cascade.package).toSet(); |
363 for (var id in invalidIds) { | 342 for (var id in invalidIds) { |
364 newIds.remove(id); | 343 newIds.remove(id); |
365 // TODO(nweiz): report this as a warning rather than a failing error. | 344 // TODO(nweiz): report this as a warning rather than a failing error. |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
414 } | 393 } |
415 | 394 |
416 /// Emit the pass-through asset if it's not being emitted already. | 395 /// Emit the pass-through asset if it's not being emitted already. |
417 void _emitPassThrough() { | 396 void _emitPassThrough() { |
418 assert(!_outputControllers.containsKey(primary.id)); | 397 assert(!_outputControllers.containsKey(primary.id)); |
419 | 398 |
420 if (_consumePrimary) return; | 399 if (_consumePrimary) return; |
421 if (_passThroughController == null) { | 400 if (_passThroughController == null) { |
422 _passThroughController = new AssetNodeController.from(primary); | 401 _passThroughController = new AssetNodeController.from(primary); |
423 _onAssetController.add(_passThroughController.node); | 402 _onAssetController.add(_passThroughController.node); |
424 } else { | 403 } else if (primary.state.isDirty) { |
| 404 _passThroughController.setDirty(); |
| 405 } else if (!_passThroughController.node.state.isAvailable) { |
425 _passThroughController.setAvailable(primary.asset); | 406 _passThroughController.setAvailable(primary.asset); |
426 } | 407 } |
427 } | 408 } |
428 | 409 |
429 /// Stop emitting the pass-through asset if it's being emitted already. | 410 /// Stop emitting the pass-through asset if it's being emitted already. |
430 void _dontEmitPassThrough() { | 411 void _dontEmitPassThrough() { |
431 if (_passThroughController == null) return; | 412 if (_passThroughController == null) return; |
432 _passThroughController.setRemoved(); | 413 _passThroughController.setRemoved(); |
433 _passThroughController = null; | 414 _passThroughController = null; |
434 } | 415 } |
435 | 416 |
436 BarbackException _wrapException(error, StackTrace stackTrace) { | 417 BarbackException _wrapException(error, StackTrace stackTrace) { |
437 if (error is! AssetNotFoundException) { | 418 if (error is! AssetNotFoundException) { |
438 return new TransformerException(info, error, stackTrace); | 419 return new TransformerException(info, error, stackTrace); |
439 } else { | 420 } else { |
440 return new MissingInputException(info, error.id); | 421 return new MissingInputException(info, error.id); |
441 } | 422 } |
442 } | 423 } |
443 | 424 |
444 String toString() => | 425 String toString() => |
445 "transform node in $_location for $transformer on $primary"; | 426 "transform node in $_location for $transformer on $primary"; |
446 } | 427 } |
447 | 428 |
448 /// The enum of states that [TransformNode] can be in. | 429 /// The enum of states that [TransformNode] can be in. |
449 class _TransformNodeState { | 430 class _State { |
450 /// The transform node is running [Transformer.isPrimary] or | 431 /// The transform is running [Transformer.isPrimary]. |
451 /// [Transformer.apply] and doesn't need to re-run them. | |
452 /// | 432 /// |
453 /// If there are no external changes by the time the processing finishes, this | 433 /// This is the initial state of the transformer. Once [Transformer.isPrimary] |
454 /// will transition to [APPLIED] or [NOT_PRIMARY] depending on the result of | 434 /// finishes running, this will transition to [APPLYING] if the input is |
455 /// [Transformer.isPrimary]. If the primary input changes, this will | 435 /// primary, or [NOT_PRIMARY] if it's not. |
456 /// transition to [NEEDS_IS_PRIMARY]. If a secondary input changes, this will | 436 static final COMPUTING_IS_PRIMARY = const _State._("computing isPrimary"); |
457 /// transition to [NEEDS_APPLY]. | |
458 static final PROCESSING = const _TransformNodeState._("processing"); | |
459 | 437 |
460 /// The transform is running [Transformer.isPrimary] or [Transformer.apply], | 438 /// The transform is running [Transformer.apply]. |
461 /// but since it started the primary input changed, so it will need to re-run | |
462 /// [Transformer.isPrimary]. | |
463 /// | 439 /// |
464 /// This will always transition to [Transformer.PROCESSING]. | 440 /// If an input changes while in this state, it will transition to |
465 static final NEEDS_IS_PRIMARY = | 441 /// [NEEDS_APPLY]. If the [TransformNode] is still in this state when |
466 const _TransformNodeState._("needs isPrimary"); | 442 /// [Transformer.apply] finishes running, it will transition to [APPLIED]. |
| 443 static final APPLYING = const _State._("applying"); |
467 | 444 |
468 /// The transform is running [Transformer.apply], but since it started a | 445 /// The transform is running [Transformer.apply], but an input changed after |
469 /// secondary input changed, so it will need to re-run [Transformer.apply]. | 446 /// it started, so it will need to re-run [Transformer.apply]. |
470 /// | 447 /// |
471 /// If there are no external changes by the time [Transformer.apply] finishes, | 448 /// This will transition to [APPLYING] once [Transformer.apply] finishes |
472 /// this will transition to [PROCESSING]. If the primary input changes, this | 449 /// running. |
473 /// will transition to [NEEDS_IS_PRIMARY]. | 450 static final NEEDS_APPLY = const _State._("needs apply"); |
474 static final NEEDS_APPLY = const _TransformNodeState._("needs apply"); | |
475 | 451 |
476 /// The transform has finished running [Transformer.apply], whether or not it | 452 /// The transform has finished running [Transformer.apply], whether or not it |
477 /// emitted an error. | 453 /// emitted an error. |
478 /// | 454 /// |
479 /// If the primary input or a secondary input changes, this will transition to | 455 /// If an input changes, this will transition to [APPLYING]. |
480 /// [PROCESSING]. | 456 static final APPLIED = const _State._("applied"); |
481 static final APPLIED = const _TransformNodeState._("applied"); | |
482 | 457 |
483 /// The transform has finished running [Transformer.isPrimary], which returned | 458 /// The transform has finished running [Transformer.isPrimary], which returned |
484 /// `false`. | 459 /// `false`. |
485 /// | 460 /// |
486 /// If the primary input changes, this will transition to [PROCESSING]. | 461 /// This will never transition to another state. |
487 static final NOT_PRIMARY = const _TransformNodeState._("not primary"); | 462 static final NOT_PRIMARY = const _State._("not primary"); |
488 | |
489 /// Whether [this] is [PROCESSING]. | |
490 bool get isProcessing => this == _TransformNodeState.PROCESSING; | |
491 | |
492 /// Whether [this] is [NEEDS_IS_PRIMARY]. | |
493 bool get needsIsPrimary => this == _TransformNodeState.NEEDS_IS_PRIMARY; | |
494 | |
495 /// Whether [this] is [NEEDS_APPLY]. | |
496 bool get needsApply => this == _TransformNodeState.NEEDS_APPLY; | |
497 | |
498 /// Whether [this] is [APPLIED]. | |
499 bool get isApplied => this == _TransformNodeState.APPLIED; | |
500 | |
501 /// Whether [this] is [NOT_PRIMARY]. | |
502 bool get isNotPrimary => this == _TransformNodeState.NOT_PRIMARY; | |
503 | |
504 /// Whether the transform has finished running [Transformer.isPrimary] and | |
505 /// [Transformer.apply]. | |
506 /// | |
507 /// Specifically, whether [this] is [APPLIED] or [NOT_PRIMARY]. | |
508 bool get isDone => isApplied || isNotPrimary; | |
509 | 463 |
510 final String name; | 464 final String name; |
511 | 465 |
512 const _TransformNodeState._(this.name); | 466 const _State._(this.name); |
513 | 467 |
514 String toString() => name; | 468 String toString() => name; |
515 } | 469 } |
OLD | NEW |