| 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 import 'dart:async'; | 5 import 'dart:async'; |
| 6 import 'dart:convert'; | 6 import 'dart:convert'; |
| 7 import 'dart:math' as math; | 7 import 'dart:math' as math; |
| 8 import 'dart:typed_data'; |
| 8 | 9 |
| 9 import 'package:async/async.dart' hide StreamQueue; | 10 import 'package:async/async.dart' hide StreamQueue; |
| 10 import 'package:path/path.dart' as p; | 11 import 'package:path/path.dart' as p; |
| 11 import 'package:shelf/shelf.dart' as shelf; | 12 import 'package:shelf/shelf.dart' as shelf; |
| 12 import 'package:stack_trace/stack_trace.dart'; | 13 import 'package:stack_trace/stack_trace.dart'; |
| 13 | 14 |
| 14 import 'backend/operating_system.dart'; | 15 import 'backend/operating_system.dart'; |
| 15 import 'util/path_handler.dart'; | 16 import 'util/path_handler.dart'; |
| 16 import 'util/stream_queue.dart'; | 17 import 'util/stream_queue.dart'; |
| 17 | 18 |
| (...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 186 result.add(element); | 187 result.add(element); |
| 187 } | 188 } |
| 188 } | 189 } |
| 189 } | 190 } |
| 190 helper(nested); | 191 helper(nested); |
| 191 return result; | 192 return result; |
| 192 } | 193 } |
| 193 | 194 |
| 194 /// Creates a new map from [map] with new keys and values. | 195 /// Creates a new map from [map] with new keys and values. |
| 195 /// | 196 /// |
| 196 /// The return values of [key] are used as the keys and the return values of | 197 /// The return values of [keyFn] are used as the keys and the return values of |
| 197 /// [value] are used as the values for the new map. | 198 /// [valueFn] are used as the values for the new map. |
| 198 /// | 199 Map/*<K2, V2>*/ mapMap/*<K1, V1, K2, V2>*/(Map/*<K1, V1>*/ map, |
| 199 /// [key] defaults to returning the original key and [value] defaults to | 200 {/*=K2*/ key(/*=K1*/ key, /*=V1*/ value), |
| 200 /// returning the original value. | 201 /*=V2*/ value(/*=K1*/ key, /*=V1*/ value)}) { |
| 201 Map mapMap(Map map, {key(key, value), value(key, value)}) { | 202 key ??= (key, _) => key as dynamic/*=K2*/; |
| 202 if (key == null) key = (key, _) => key; | 203 value ??= (_, value) => value as dynamic/*=V2*/; |
| 203 if (value == null) value = (_, value) => value; | |
| 204 | 204 |
| 205 var result = {}; | 205 return new Map.fromIterable(map.keys, |
| 206 map.forEach((mapKey, mapValue) { | 206 key: (mapKey) => key(mapKey as dynamic/*=K1*/, map[mapKey]), |
| 207 result[key(mapKey, mapValue)] = value(mapKey, mapValue); | 207 value: (mapKey) => value(mapKey as dynamic/*=K1*/, map[mapKey])); |
| 208 }); | |
| 209 return result; | |
| 210 } | 208 } |
| 211 | 209 |
| 212 /// Returns a new map with all values in both [map1] and [map2]. | 210 /// Returns a new map with all values in both [map1] and [map2]. |
| 213 /// | 211 /// |
| 214 /// If there are conflicting keys, [value] is used to merge them. If it's | 212 /// If there are conflicting keys, [value] is used to merge them. If it's |
| 215 /// not passed, [map2]'s value wins. | 213 /// not passed, [map2]'s value wins. |
| 216 Map mergeMaps(Map map1, Map map2, {value(value1, value2)}) { | 214 Map/*<K, V>*/ mergeMaps/*<K, V>*/(Map/*<K, V>*/ map1, Map/*<K, V>*/ map2, |
| 217 var result = new Map.from(map1); | 215 {/*=V*/ value(/*=V*/ value1, /*=V*/ value2)}) { |
| 216 var result = new Map/*<K, V>*/.from(map1); |
| 218 map2.forEach((key, mapValue) { | 217 map2.forEach((key, mapValue) { |
| 219 if (value == null || !result.containsKey(key)) { | 218 if (value == null || !result.containsKey(key)) { |
| 220 result[key] = mapValue; | 219 result[key] = mapValue; |
| 221 } else { | 220 } else { |
| 222 result[key] = value(result[key], mapValue); | 221 result[key] = value(result[key], mapValue); |
| 223 } | 222 } |
| 224 }); | 223 }); |
| 225 return result; | 224 return result; |
| 226 } | 225 } |
| 227 | 226 |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 288 if (minutes == 0 || seconds != 0) { | 287 if (minutes == 0 || seconds != 0) { |
| 289 if (minutes != 0) buffer.write(", "); | 288 if (minutes != 0) buffer.write(", "); |
| 290 buffer.write(seconds); | 289 buffer.write(seconds); |
| 291 if (decaseconds != 0) buffer.write(".$decaseconds"); | 290 if (decaseconds != 0) buffer.write(".$decaseconds"); |
| 292 buffer.write(" seconds"); | 291 buffer.write(" seconds"); |
| 293 } | 292 } |
| 294 | 293 |
| 295 return buffer.toString(); | 294 return buffer.toString(); |
| 296 } | 295 } |
| 297 | 296 |
| 298 /// Merges [streams] into a single stream that emits events from all sources. | |
| 299 Stream mergeStreams(Iterable<Stream> streamIter) { | |
| 300 var streams = streamIter.toList(); | |
| 301 | |
| 302 var subscriptions = new Set(); | |
| 303 var controller; | |
| 304 controller = new StreamController(sync: true, onListen: () { | |
| 305 for (var stream in streams) { | |
| 306 var subscription; | |
| 307 subscription = stream.listen( | |
| 308 controller.add, | |
| 309 onError: controller.addError, | |
| 310 onDone: () { | |
| 311 subscriptions.remove(subscription); | |
| 312 if (subscriptions.isEmpty) controller.close(); | |
| 313 }); | |
| 314 subscriptions.add(subscription); | |
| 315 } | |
| 316 }, onPause: () { | |
| 317 for (var subscription in subscriptions) { | |
| 318 subscription.pause(); | |
| 319 } | |
| 320 }, onResume: () { | |
| 321 for (var subscription in subscriptions) { | |
| 322 subscription.resume(); | |
| 323 } | |
| 324 }, onCancel: () { | |
| 325 for (var subscription in subscriptions) { | |
| 326 subscription.cancel(); | |
| 327 } | |
| 328 }); | |
| 329 | |
| 330 return controller.stream; | |
| 331 } | |
| 332 | |
| 333 /// Returns the first value [stream] emits, or `null` if [stream] closes before | 297 /// Returns the first value [stream] emits, or `null` if [stream] closes before |
| 334 /// emitting a value. | 298 /// emitting a value. |
| 335 Future maybeFirst(Stream stream) { | 299 Future maybeFirst(Stream stream) { |
| 336 var completer = new Completer(); | 300 var completer = new Completer(); |
| 337 | 301 |
| 338 var subscription; | 302 var subscription; |
| 339 subscription = stream.listen((data) { | 303 subscription = stream.listen((data) { |
| 340 completer.complete(data); | 304 completer.complete(data); |
| 341 subscription.cancel(); | 305 subscription.cancel(); |
| 342 }, onError: (error, stackTrace) { | 306 }, onError: (error, stackTrace) { |
| (...skipping 26 matching lines...) Expand all Loading... |
| 369 })); | 333 })); |
| 370 | 334 |
| 371 return completer.operation; | 335 return completer.operation; |
| 372 } | 336 } |
| 373 | 337 |
| 374 /// Returns a single-subscription stream that emits the results of [operations] | 338 /// Returns a single-subscription stream that emits the results of [operations] |
| 375 /// in the order they complete. | 339 /// in the order they complete. |
| 376 /// | 340 /// |
| 377 /// If the subscription is canceled, any pending operations are canceled as | 341 /// If the subscription is canceled, any pending operations are canceled as |
| 378 /// well. | 342 /// well. |
| 379 Stream inCompletionOrder(Iterable<CancelableOperation> operations) { | 343 Stream/*<T>*/ inCompletionOrder/*<T>*/( |
| 344 Iterable<CancelableOperation/*<T>*/> operations) { |
| 380 var operationSet = operations.toSet(); | 345 var operationSet = operations.toSet(); |
| 381 var controller = new StreamController(sync: true, onCancel: () { | 346 var controller = new StreamController/*<T>*/(sync: true, onCancel: () { |
| 382 return Future.wait(operationSet.map((operation) => operation.cancel())); | 347 return Future.wait(operationSet.map((operation) => operation.cancel())); |
| 383 }); | 348 }); |
| 384 | 349 |
| 385 for (var operation in operationSet) { | 350 for (var operation in operationSet) { |
| 386 operation.value.then(controller.add).catchError(controller.addError) | 351 operation.value.then((value) => controller.add(value)) |
| 352 .catchError(controller.addError) |
| 387 .whenComplete(() { | 353 .whenComplete(() { |
| 388 operationSet.remove(operation); | 354 operationSet.remove(operation); |
| 389 if (operationSet.isEmpty) controller.close(); | 355 if (operationSet.isEmpty) controller.close(); |
| 390 }); | 356 }); |
| 391 } | 357 } |
| 392 | 358 |
| 393 return controller.stream; | 359 return controller.stream; |
| 394 } | 360 } |
| 395 | 361 |
| 396 /// Returns a stream that emits [error] and [stackTrace], then closes. | 362 /// Returns a stream that emits [error] and [stackTrace], then closes. |
| (...skipping 13 matching lines...) Expand all Loading... |
| 410 void invoke(fn()) { | 376 void invoke(fn()) { |
| 411 fn(); | 377 fn(); |
| 412 } | 378 } |
| 413 | 379 |
| 414 /// Returns a random base64 string containing [bytes] bytes of data. | 380 /// Returns a random base64 string containing [bytes] bytes of data. |
| 415 /// | 381 /// |
| 416 /// [seed] is passed to [math.Random]; [urlSafe] and [addLineSeparator] are | 382 /// [seed] is passed to [math.Random]; [urlSafe] and [addLineSeparator] are |
| 417 /// passed to [CryptoUtils.bytesToBase64]. | 383 /// passed to [CryptoUtils.bytesToBase64]. |
| 418 String randomBase64(int bytes, {int seed}) { | 384 String randomBase64(int bytes, {int seed}) { |
| 419 var random = new math.Random(seed); | 385 var random = new math.Random(seed); |
| 420 var data = []; | 386 var data = new Uint8List(bytes); |
| 421 for (var i = 0; i < bytes; i++) { | 387 for (var i = 0; i < bytes; i++) { |
| 422 data.add(random.nextInt(256)); | 388 data[i] = random.nextInt(256); |
| 423 } | 389 } |
| 424 return BASE64.encode(data); | 390 return BASE64.encode(data); |
| 425 } | 391 } |
| 426 | 392 |
| 427 /// Returns middleware that nests all requests beneath the URL prefix [beneath]. | 393 /// Returns middleware that nests all requests beneath the URL prefix [beneath]. |
| 428 shelf.Middleware nestingMiddleware(String beneath) { | 394 shelf.Middleware nestingMiddleware(String beneath) { |
| 429 return (handler) { | 395 return (handler) { |
| 430 var pathHandler = new PathHandler()..add(beneath, handler); | 396 var pathHandler = new PathHandler()..add(beneath, handler); |
| 431 return pathHandler.handler; | 397 return pathHandler.handler; |
| 432 }; | 398 }; |
| 433 } | 399 } |
| OLD | NEW |