| // Copyright 2016 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import 'dart:async'; |
| |
| typedef void ErrorHandler(dynamic error, StackTrace stackTrace); |
| |
| /// A singleton for application functionality. This singleton can be different |
| /// on a per-Zone basis. |
| AppContext get context => Zone.current['context']; |
| |
| class AppContext { |
| final Map<Type, dynamic> _instances = <Type, dynamic>{}; |
| Zone _zone; |
| |
| AppContext() : _zone = Zone.current; |
| |
| bool isSet(Type type) { |
| if (_instances.containsKey(type)) |
| return true; |
| |
| final AppContext parent = _calcParent(_zone); |
| return parent != null ? parent.isSet(type) : false; |
| } |
| |
| dynamic getVariable(Type type) { |
| if (_instances.containsKey(type)) |
| return _instances[type]; |
| |
| final AppContext parent = _calcParent(_zone); |
| return parent?.getVariable(type); |
| } |
| |
| void setVariable(Type type, dynamic instance) { |
| _instances[type] = instance; |
| } |
| |
| dynamic operator[](Type type) => getVariable(type); |
| |
| dynamic putIfAbsent(Type type, dynamic ifAbsent()) { |
| dynamic value = getVariable(type); |
| if (value != null) { |
| return value; |
| } |
| value = ifAbsent(); |
| setVariable(type, value); |
| return value; |
| } |
| |
| AppContext _calcParent(Zone zone) { |
| final Zone parentZone = zone.parent; |
| if (parentZone == null) |
| return null; |
| |
| final AppContext parentContext = parentZone['context']; |
| return parentContext == this |
| ? _calcParent(parentZone) |
| : parentContext; |
| } |
| |
| Future<dynamic> runInZone(dynamic method(), { |
| ZoneBinaryCallback<dynamic, dynamic, StackTrace> onError |
| }) { |
| return runZoned( |
| () => _run(method), |
| zoneValues: <String, dynamic>{ 'context': this }, |
| onError: onError |
| ); |
| } |
| |
| Future<dynamic> _run(dynamic method()) async { |
| final Zone previousZone = _zone; |
| try { |
| _zone = Zone.current; |
| return await method(); |
| } finally { |
| _zone = previousZone; |
| } |
| } |
| } |