blob: 2ec5eb9d624194da6c6949b1e3262fca4a282880 [file] [log] [blame]
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
typedef void DebugCallback(String methodName, var arg1, var arg2);
class DebugMap<K, V> implements Map<K, V> {
final Map<K, V> sourceMap;
DebugCallback indexSetCallback;
DebugCallback putIfAbsentCallback;
DebugCallback removeCallback;
DebugMap(this.sourceMap, {DebugCallback addCallback, this.removeCallback}) {
if (addCallback != null) {
this.addCallback = addCallback;
}
}
void set addCallback(DebugCallback value) {
indexSetCallback = value;
putIfAbsentCallback = value;
}
Map<RK, RV> cast<RK, RV>() {
Map<Object, Object> self = this;
return self is Map<RK, RV> ? self : this.retype<RK, RV>();
}
Map<RK, RV> retype<RK, RV>() => Map.castFrom<K, V, RK, RV>(this);
bool containsValue(Object value) {
return sourceMap.containsValue(value);
}
bool containsKey(Object key) => sourceMap.containsKey(key);
V operator [](Object key) => sourceMap[key];
void operator []=(K key, V value) {
if (indexSetCallback != null) {
indexSetCallback('[]=', key, value);
}
sourceMap[key] = value;
}
V putIfAbsent(K key, V ifAbsent()) {
return sourceMap.putIfAbsent(key, () {
V v = ifAbsent();
if (putIfAbsentCallback != null) {
putIfAbsentCallback('putIfAbsent', key, v);
}
return v;
});
}
void addAll(Map<K, V> other) => sourceMap.addAll(other);
V remove(Object key) {
if (removeCallback != null) {
removeCallback('remove', key, sourceMap[key]);
}
return sourceMap.remove(key);
}
void clear() {
if (removeCallback != null) {
removeCallback('clear', sourceMap, null);
}
sourceMap.clear();
}
void forEach(void f(K key, V value)) => sourceMap.forEach(f);
Iterable<K> get keys => sourceMap.keys;
Iterable<V> get values => sourceMap.values;
Iterable<MapEntry<K, V>> get entries => sourceMap.entries;
void addEntries(Iterable<MapEntry<K, V>> entries) {
sourceMap.addEntries(entries);
}
Map<K2, V2> map<K2, V2>(MapEntry<K2, V2> transform(K key, V value)) =>
sourceMap.map(transform);
int get length => sourceMap.length;
bool get isEmpty => sourceMap.isEmpty;
bool get isNotEmpty => sourceMap.isNotEmpty;
V update(K key, V update(V value), {V ifAbsent()}) =>
sourceMap.update(key, update, ifAbsent: ifAbsent);
void updateAll(V update(K key, V value)) {
sourceMap.updateAll(update);
}
void removeWhere(bool test(K key, V value)) {
sourceMap.removeWhere(test);
}
}
class DebugIterable<E> implements Iterable<E> {
final Iterable<E> iterable;
DebugIterable(this.iterable);
Iterator<E> get iterator => iterable.iterator;
Iterable<R> cast<R>() {
Iterable<Object> self = this;
return self is Iterable<R> ? self : this.retype<R>();
}
Iterable<R> retype<R>() => Iterable.castFrom<E, R>(this);
Iterable<T> map<T>(T f(E element)) => iterable.map(f);
Iterable<E> where(bool test(E element)) => iterable.where(test);
Iterable<T> expand<T>(Iterable<T> f(E element)) => iterable.expand(f);
bool contains(Object element) => iterable.contains(element);
void forEach(void f(E element)) => iterable.forEach(f);
E reduce(E combine(E value, E element)) => iterable.reduce(combine);
T fold<T>(T initialValue, T combine(T previousValue, E element)) {
return iterable.fold(initialValue, combine);
}
bool every(bool test(E element)) => iterable.every(test);
String join([String separator = ""]) => iterable.join(separator);
bool any(bool test(E element)) => iterable.any(test);
List<E> toList({bool growable: true}) {
return iterable.toList(growable: growable);
}
Set<E> toSet() => iterable.toSet();
int get length => iterable.length;
bool get isEmpty => iterable.isEmpty;
bool get isNotEmpty => iterable.isNotEmpty;
Iterable<E> take(int n) => iterable.take(n);
Iterable<E> takeWhile(bool test(E value)) => iterable.takeWhile(test);
Iterable<E> skip(int n) => iterable.skip(n);
Iterable<E> skipWhile(bool test(E value)) => iterable.skipWhile(test);
E get first => iterable.first;
E get last => iterable.last;
E get single => iterable.single;
E firstWhere(bool test(E element), {E orElse()}) {
return iterable.firstWhere(test, orElse: orElse);
}
E lastWhere(bool test(E element), {E orElse()}) {
return iterable.lastWhere(test, orElse: orElse);
}
E singleWhere(bool test(E element), {E orElse()}) =>
iterable.singleWhere(test, orElse: orElse);
E elementAt(int index) => iterable.elementAt(index);
Iterable<E> followedBy(Iterable<E> other) => iterable.followedBy(other);
Iterable<T> whereType<T>() => iterable.whereType<T>();
String toString() => iterable.toString();
}
class DebugList<E> extends DebugIterable<E> implements List<E> {
DebugCallback addCallback;
DebugCallback addAllCallback;
DebugList(List<E> list, {this.addCallback, this.addAllCallback})
: super(list);
List<E> get list => iterable;
List<R> cast<R>() {
List<Object> self = this;
return self is List<R> ? self : this.retype<R>();
}
List<R> retype<R>() => List.castFrom<E, R>(this);
List<E> operator +(List<E> other) => list + other;
E operator [](int index) => list[index];
void operator []=(int index, E value) {
list[index] = value;
}
void set first(E element) {
list.first = element;
}
void set last(E element) {
list.last = element;
}
int get length => list.length;
void set length(int newLength) {
list.length = newLength;
}
void add(E value) {
if (addCallback != null) {
addCallback('add', value, null);
}
list.add(value);
}
void addAll(Iterable<E> iterable) {
if (addAllCallback != null) {
addAllCallback('addAll', iterable, null);
}
list.addAll(iterable);
}
Iterable<E> get reversed => list.reversed;
void sort([int compare(E a, E b)]) => list.sort(compare);
void shuffle([random]) => list.shuffle(random);
int indexOf(E element, [int start = 0]) => list.indexOf(element, start);
int indexWhere(bool test(E element), [int start = 0]) =>
list.indexWhere(test, start);
int lastIndexOf(E element, [int start]) => list.lastIndexOf(element, start);
int lastIndexWhere(bool test(E element), [int start]) =>
list.lastIndexWhere(test, start);
void clear() => list.clear();
void insert(int index, E element) => list.insert(index, element);
void insertAll(int index, Iterable<E> iterable) {
list.insertAll(index, iterable);
}
void setAll(int index, Iterable<E> iterable) => list.setAll(index, iterable);
bool remove(Object value) => list.remove(value);
E removeAt(int index) => list.removeAt(index);
E removeLast() => list.removeLast();
void removeWhere(bool test(E element)) => list.removeWhere(test);
void retainWhere(bool test(E element)) => list.retainWhere(test);
List<E> sublist(int start, [int end]) => list.sublist(start, end);
Iterable<E> getRange(int start, int end) => list.getRange(start, end);
void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) {
list.setRange(start, end, iterable, skipCount);
}
void removeRange(int start, int end) {
list.removeRange(start, end);
}
void fillRange(int start, int end, [E fillValue]) {
list.fillRange(start, end, fillValue);
}
void replaceRange(int start, int end, Iterable<E> replacement) {
list.replaceRange(start, end, replacement);
}
Map<int, E> asMap() => list.asMap();
}
class DebugSet<E> extends DebugIterable<E> implements Set<E> {
DebugCallback addCallback;
DebugSet(Set<E> set, {this.addCallback}) : super(set);
Set<E> get set => iterable;
Set<R> cast<R>() {
Set<Object> self = this;
return self is Set<R> ? self : this.retype<R>();
}
Set<R> retype<R>() => Set.castFrom<E, R>(this);
bool contains(Object value) => set.contains(value);
bool add(E value) {
if (addCallback != null) {
addCallback('add', value, null);
}
return set.add(value);
}
void addAll(Iterable<E> elements) {
elements.forEach(add);
}
bool remove(Object value) => set.remove(value);
E lookup(Object object) => set.lookup(object);
void removeAll(Iterable<Object> elements) => set.removeAll(elements);
void retainAll(Iterable<Object> elements) => set.retainAll(elements);
void removeWhere(bool test(E element)) => set.removeWhere(test);
void retainWhere(bool test(E element)) => set.retainWhere(test);
bool containsAll(Iterable<Object> other) => set.containsAll(other);
Set<E> intersection(Set<Object> other) => set.intersection(other);
Set<E> union(Set<E> other) => set.union(other);
Set<E> difference(Set<Object> other) => set.difference(other);
void clear() => set.clear();
Set<E> toSet() => set.toSet();
}
/// Throws an exception if the runtime type of [object] is not in
/// [runtimeTypes].
///
/// Use this to gradually build the set of actual runtime values of [object]
/// at the call site by running test programs and adding to [runtimeTypes] when
/// new type are found.
void assertType(String name, List<String> runtimeTypes, var object,
{bool showObjects: false}) {
String runtimeType = '${object.runtimeType}';
if (runtimeTypes != null && runtimeTypes.contains(runtimeType)) return;
throw '$name: $runtimeType'
'${showObjects ? ' ($object)' : ''}';
}
/// Callback for the [addCallback] of [DebugMap] that throws an exception if
/// the runtime type of key/value pairs are not in [runtimeTypes].
///
/// Use this to gradually build the set of actual runtime values of key/value
/// pairs of a map by running test programs and adding to [runtimeTypes] when
/// new type are found.
class MapTypeAsserter {
final String name;
final Map<String, List<String>> runtimeTypes;
final bool showObjects;
const MapTypeAsserter(this.name, this.runtimeTypes,
{bool this.showObjects: false});
void call(String methodName, var key, var value) {
check(key, value, '$methodName: ');
}
void check(var key, var value, [String text = '']) {
String keyType = '${key.runtimeType}';
String valueType = '${value.runtimeType}';
List<String> valuesTypes = runtimeTypes[keyType];
if (valuesTypes != null && valuesTypes.contains(valueType)) return;
throw '$name: $text$keyType => $valueType'
'${showObjects ? ' ($key => $value)' : ''}';
}
}
/// Callback for the [addCallback] of [DebugSet] or [DebugList] that throws an
/// exception if the runtime type of the elements are not in [runtimeTypes].
///
/// Use this to gradually build the set of actual runtime values of the elements
/// of a collection by running test programs and adding to [runtimeTypes] when
/// new type are found.
class CollectionTypeAsserter {
final String name;
final List<String> runtimeTypes;
final bool showObjects;
const CollectionTypeAsserter(this.name, this.runtimeTypes,
{bool this.showObjects: false});
void call(String methodName, var element, _) {
check(element, '$methodName: ');
}
void check(var element, [String text = '']) {
String elementType = '${element.runtimeType}';
if (runtimeTypes.contains(elementType)) return;
throw '$name: $text$elementType'
'${showObjects ? ' ($element)' : ''}';
}
}