| 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 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 55 /// or removed, the appropriate portion of the asset graph is dirtied before | 55 /// or removed, the appropriate portion of the asset graph is dirtied before |
| 56 /// any [Barback.getAssetById] calls emit newly-incorrect values. | 56 /// any [Barback.getAssetById] calls emit newly-incorrect values. |
| 57 Stream<AssetState> get onStateChange => _stateChangeController.stream; | 57 Stream<AssetState> get onStateChange => _stateChangeController.stream; |
| 58 | 58 |
| 59 /// This is synchronous so that a source being updated will always be | 59 /// This is synchronous so that a source being updated will always be |
| 60 /// propagated through the build graph before anything that depends on it is | 60 /// propagated through the build graph before anything that depends on it is |
| 61 /// requested. | 61 /// requested. |
| 62 final _stateChangeController = | 62 final _stateChangeController = |
| 63 new StreamController<AssetState>.broadcast(sync: true); | 63 new StreamController<AssetState>.broadcast(sync: true); |
| 64 | 64 |
| 65 /// Returns a Future that completes when the node's asset is available. | 65 /// Calls [callback] when the node's asset is available. |
| 66 /// | 66 /// |
| 67 /// If the asset is currently available, this completes synchronously to | 67 /// If the asset is currently available, this calls [callback] synchronously |
| 68 /// ensure that the asset is still available in the [Future.then] callback. | 68 /// to ensure that the asset is still available. |
| 69 /// | 69 /// |
| 70 /// If the asset is removed before becoming available, this will throw an | 70 /// The return value of [callback] is piped to the returned Future. If the |
| 71 /// [AssetNotFoundException]. | 71 /// asset is removed before becoming available, the returned future will throw |
| 72 Future<Asset> get whenAvailable { | 72 /// an [AssetNotFoundException]. |
| 73 return _waitForState((state) => state.isAvailable || state.isRemoved) | 73 Future whenAvailable(callback(Asset asset)) { |
| 74 .then((state) { | 74 return _waitForState((state) => state.isAvailable || state.isRemoved, |
| 75 (state) { |
| 75 if (state.isRemoved) throw new AssetNotFoundException(id); | 76 if (state.isRemoved) throw new AssetNotFoundException(id); |
| 76 return asset; | 77 return callback(asset); |
| 77 }); | 78 }); |
| 78 } | 79 } |
| 79 | 80 |
| 80 /// Returns a Future that completes when the node's asset is removed. | 81 /// Calls [callback] when the node's asset is removed. |
| 81 /// | 82 /// |
| 82 /// If the asset is already removed when this is called, it completes | 83 /// If the asset is already removed when this is called, it calls [callback] |
| 83 /// synchronously. | 84 /// synchronously. |
| 84 Future get whenRemoved => _waitForState((state) => state.isRemoved); | 85 /// |
| 86 /// The return value of [callback] is piped to the returned Future. |
| 87 Future whenRemoved(callback()) => |
| 88 _waitForState((state) => state.isRemoved, (_) => callback()); |
| 85 | 89 |
| 86 /// Runs [callback] repeatedly until the node's asset has maintained the same | 90 /// Runs [callback] repeatedly until the node's asset has maintained the same |
| 87 /// value for the duration. | 91 /// value for the duration. |
| 88 /// | 92 /// |
| 89 /// This will run [callback] as soon as the asset is available (synchronously | 93 /// This will run [callback] as soon as the asset is available (synchronously |
| 90 /// if it's available immediately). If the [state] changes at all while | 94 /// if it's available immediately). If the [state] changes at all while |
| 91 /// waiting for the Future returned by [callback] to complete, it will be | 95 /// waiting for the Future returned by [callback] to complete, it will be |
| 92 /// re-run as soon as it completes and the asset is available again. This will | 96 /// re-run as soon as it completes and the asset is available again. This will |
| 93 /// continue until [state] doesn't change at all. | 97 /// continue until [state] doesn't change at all. |
| 94 /// | 98 /// |
| 95 /// If this asset is removed, this will throw an [AssetNotFoundException] as | 99 /// If this asset is removed, this will throw an [AssetNotFoundException] as |
| 96 /// soon as [callback]'s Future is finished running. | 100 /// soon as [callback]'s Future is finished running. |
| 97 Future tryUntilStable(Future callback(Asset asset)) { | 101 Future tryUntilStable(Future callback(Asset asset)) { |
| 98 return whenAvailable.then((asset) { | 102 return whenAvailable((asset) { |
| 99 var modifiedDuringCallback = false; | 103 var modifiedDuringCallback = false; |
| 100 var subscription; | 104 var subscription; |
| 101 subscription = onStateChange.listen((_) { | 105 subscription = onStateChange.listen((_) { |
| 102 modifiedDuringCallback = true; | 106 modifiedDuringCallback = true; |
| 103 subscription.cancel(); | 107 subscription.cancel(); |
| 104 }); | 108 }); |
| 105 | 109 |
| 106 return callback(asset).then((result) { | 110 return callback(asset).then((result) { |
| 107 subscription.cancel(); | 111 subscription.cancel(); |
| 108 | 112 |
| 109 // If the asset was modified at all while running the callback, the | 113 // If the asset was modified at all while running the callback, the |
| 110 // result was invalid and we should try again. | 114 // result was invalid and we should try again. |
| 111 if (modifiedDuringCallback) return tryUntilStable(callback); | 115 if (modifiedDuringCallback) return tryUntilStable(callback); |
| 112 return result; | 116 return result; |
| 113 }); | 117 }); |
| 114 }); | 118 }); |
| 115 } | 119 } |
| 116 | 120 |
| 117 /// Returns a Future that completes as soon as the node is in a state that | 121 /// Calls [callback] as soon as the node is in a state that matches [test]. |
| 118 /// matches [test]. | |
| 119 /// | 122 /// |
| 120 /// The Future completes synchronously if this is already in such a state. | 123 /// [callback] is called synchronously if this is already in such a state. |
| 121 Future<AssetState> _waitForState(bool test(AssetState state)) { | 124 /// |
| 122 if (test(state)) return new Future.sync(() => state); | 125 /// The return value of [callback] is piped to the returned Future. |
| 123 return onStateChange.firstWhere(test); | 126 Future _waitForState(bool test(AssetState state), |
| 127 callback(AssetState state)) { |
| 128 if (test(state)) return new Future.sync(() => callback(state)); |
| 129 return onStateChange.firstWhere(test).then((_) => callback(state)); |
| 124 } | 130 } |
| 125 | 131 |
| 126 AssetNode._(this.id, this._transform, this._origin) | 132 AssetNode._(this.id, this._transform, this._origin) |
| 127 : _state = AssetState.DIRTY; | 133 : _state = AssetState.DIRTY; |
| 128 | 134 |
| 129 AssetNode._available(Asset asset, this._transform, this._origin) | 135 AssetNode._available(Asset asset, this._transform, this._origin) |
| 130 : id = asset.id, | 136 : id = asset.id, |
| 131 _asset = asset, | 137 _asset = asset, |
| 132 _state = AssetState.AVAILABLE; | 138 _state = AssetState.AVAILABLE; |
| 133 } | 139 } |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 218 | 224 |
| 219 /// Whether this state is [AssetState.DIRTY]. | 225 /// Whether this state is [AssetState.DIRTY]. |
| 220 bool get isDirty => this == AssetState.DIRTY; | 226 bool get isDirty => this == AssetState.DIRTY; |
| 221 | 227 |
| 222 final String name; | 228 final String name; |
| 223 | 229 |
| 224 const AssetState._(this.name); | 230 const AssetState._(this.name); |
| 225 | 231 |
| 226 String toString() => name; | 232 String toString() => name; |
| 227 } | 233 } |
| OLD | NEW |