context.dart 2 KB
Newer Older
1 2 3 4 5 6
// 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';

7
typedef void ErrorHandler(dynamic error, StackTrace stackTrace);
8

9 10
/// A singleton for application functionality. This singleton can be different
/// on a per-Zone basis.
11
AppContext get context => Zone.current['context'];
12

13
class AppContext {
14
  final Map<Type, dynamic> _instances = <Type, dynamic>{};
15
  Zone _zone;
16

17 18
  AppContext() : _zone = Zone.current;

19 20 21 22
  bool isSet(Type type) {
    if (_instances.containsKey(type))
      return true;

23
    final AppContext parent = _calcParent(_zone);
24 25 26
    return parent != null ? parent.isSet(type) : false;
  }

27 28 29
  dynamic getVariable(Type type) {
    if (_instances.containsKey(type))
      return _instances[type];
30

31
    final AppContext parent = _calcParent(_zone);
32 33
    return parent?.getVariable(type);
  }
34

35 36 37
  void setVariable(Type type, dynamic instance) {
    _instances[type] = instance;
  }
38

39
  dynamic operator[](Type type) => getVariable(type);
40

41 42 43 44 45 46 47 48 49
  dynamic putIfAbsent(Type type, dynamic ifAbsent()) {
    dynamic value = getVariable(type);
    if (value != null) {
      return value;
    }
    value = ifAbsent();
    setVariable(type, value);
    return value;
  }
50

51
  AppContext _calcParent(Zone zone) {
52
    final Zone parentZone = zone.parent;
53
    if (parentZone == null)
54
      return null;
55

56
    final AppContext parentContext = parentZone['context'];
57 58 59
    return parentContext == this
        ? _calcParent(parentZone)
        : parentContext;
60 61
  }

62
  Future<dynamic> runInZone(dynamic method(), {
63 64
    ZoneBinaryCallback<dynamic, dynamic, StackTrace> onError
  }) {
65
    return runZoned(
66
      () => _run(method),
67 68 69
      zoneValues: <String, dynamic>{ 'context': this },
      onError: onError
    );
70
  }
71

72
  Future<dynamic> _run(dynamic method()) async {
73
    final Zone previousZone = _zone;
74 75 76 77
    try {
      _zone = Zone.current;
      return await method();
    } finally {
78
      _zone = previousZone;
79 80
    }
  }
81
}